Skip to content

Commit ccccf41

Browse files
authored
Cypress setup (#17) (#123)
* feat: added Unit testing using Jest for utils file (#15) * fix: update import path for Kubeflow styles * fix: update build scripts to ensure CSS assets are copied correctly * fix: enhance frontend dependency installation and style setup * fix: enhance frontend dependency installation and style setup * fix: enhance frontend dependency installation and style setup * feat: setup Jest and __mocks__ for unit testing * feat: enhance type definitions and add tests for predictor extension specifications * fix: format code for consistency in utils.jest.spec.ts * fix: update unit test command to use Jest instead of production --------- * feat: add Cypress support for end-to-end testing and new serve scripts (#16) --------- Signed-off-by: LogicalGuy77 <[email protected]> Signed-off-by: Harshit Nayan <[email protected]>
1 parent 0e94887 commit ccccf41

File tree

10 files changed

+4069
-86
lines changed

10 files changed

+4069
-86
lines changed

frontend/angular.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@
160160
},
161161
"defaultProject": "frontend",
162162
"cli": {
163-
"defaultCollection": "@angular-eslint/schematics"
163+
"defaultCollection": "@angular-eslint/schematics",
164+
"analytics": false
164165
}
165166
}

frontend/cypress.config.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { defineConfig } from 'cypress'
2+
3+
export default defineConfig({
4+
e2e: {
5+
baseUrl: 'http://localhost:4200',
6+
supportFile: 'cypress/support/e2e.ts',
7+
specPattern: 'cypress/e2e/**/*.cy.ts',
8+
viewportWidth: 1280,
9+
viewportHeight: 720,
10+
video: false,
11+
screenshotOnRunFailure: true,
12+
defaultCommandTimeout: 10000,
13+
requestTimeout: 10000,
14+
responseTimeout: 10000,
15+
},
16+
component: {
17+
devServer: {
18+
framework: 'angular',
19+
bundler: 'webpack',
20+
},
21+
specPattern: '**/*.cy.ts'
22+
}
23+
})
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
describe('KServe Models Web App - Basic Test', () => {
2+
it('should load the application and display basic elements', () => {
3+
// Visit the application
4+
cy.visit('/')
5+
6+
// Wait a moment for the app to load
7+
cy.wait(2000)
8+
9+
// Check that the page loads without crashing
10+
cy.get('body').should('exist')
11+
12+
// Check for basic Angular elements
13+
cy.get('router-outlet').should('exist')
14+
15+
// Verify the page title or any text that should be present
16+
cy.title().should('not.be.empty')
17+
18+
// Log success
19+
cy.log('Basic Cypress test passed - app is loading correctly!')
20+
})
21+
22+
it('should handle navigation', () => {
23+
cy.visit('/')
24+
25+
// Check URL
26+
cy.url().should('include', 'localhost:4200')
27+
28+
// Verify the page is interactive
29+
cy.get('body').should('be.visible')
30+
})
31+
})
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
describe('Cypress Setup Test', () => {
2+
it('should be able to visit the application', () => {
3+
cy.visit('/')
4+
5+
// Wait for Angular to load
6+
cy.waitForAngular()
7+
8+
// Check if the page has loaded by looking for basic elements
9+
cy.get('body').should('exist')
10+
11+
// Check if Angular has loaded
12+
cy.window().should('have.property', 'ng')
13+
14+
// Basic assertion that we can interact with the page
15+
cy.title().should('not.be.empty')
16+
})
17+
18+
it('should have working custom commands', () => {
19+
cy.visit('/')
20+
cy.waitForAngular()
21+
22+
// Test that our custom dataCy command works
23+
// This will fail gracefully if no data-cy attributes exist
24+
cy.get('body').should('exist')
25+
})
26+
})
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
{
2+
"inferenceServices": [
3+
{
4+
"name": "sklearn-iris",
5+
"namespace": "kubeflow-user",
6+
"ready": "True",
7+
"url": "http://sklearn-iris.kubeflow-user.example.com",
8+
"age": "2d",
9+
"status": {
10+
"conditions": [
11+
{
12+
"lastTransitionTime": "2022-09-12T10:37:31Z",
13+
"status": "True",
14+
"type": "Ready"
15+
}
16+
],
17+
"url": "http://sklearn-iris.kubeflow-user.example.com"
18+
},
19+
"spec": {
20+
"predictor": {
21+
"sklearn": {
22+
"storageUri": "gs://kfserving-examples/models/sklearn/iris",
23+
"runtimeVersion": "0.24.1",
24+
"protocolVersion": "v1"
25+
}
26+
}
27+
}
28+
},
29+
{
30+
"name": "pytorch-model",
31+
"namespace": "kubeflow-user",
32+
"ready": "False",
33+
"url": "",
34+
"age": "1h",
35+
"status": {
36+
"conditions": [
37+
{
38+
"lastTransitionTime": "2022-09-12T11:00:00Z",
39+
"status": "False",
40+
"type": "Ready",
41+
"reason": "PredictorNotReady",
42+
"message": "Predictor is not ready"
43+
}
44+
]
45+
},
46+
"spec": {
47+
"predictor": {
48+
"pytorch": {
49+
"storageUri": "gs://kfserving-examples/models/pytorch/cifar10",
50+
"runtimeVersion": "1.12.0",
51+
"protocolVersion": "v1"
52+
}
53+
}
54+
}
55+
}
56+
]
57+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"namespaces": [
3+
{
4+
"name": "default",
5+
"status": "Active"
6+
},
7+
{
8+
"name": "kubeflow",
9+
"status": "Active"
10+
},
11+
{
12+
"name": "kubeflow-user",
13+
"status": "Active"
14+
},
15+
{
16+
"name": "test-namespace",
17+
"status": "Active"
18+
}
19+
]
20+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
declare global {
2+
namespace Cypress {
3+
interface Chainable {
4+
/**
5+
* Custom command to select DOM element by data-cy attribute.
6+
* @example cy.dataCy('greeting')
7+
*/
8+
dataCy(value: string): Chainable<JQuery<HTMLElement>>
9+
10+
/**
11+
* Custom command to wait for Angular to be ready
12+
*/
13+
waitForAngular(): Chainable<void>
14+
}
15+
}
16+
}
17+
18+
Cypress.Commands.add('dataCy', (value: string) => {
19+
return cy.get(`[data-cy=${value}]`)
20+
})
21+
22+
Cypress.Commands.add('waitForAngular', () => {
23+
cy.window().then((win: any) => {
24+
return new Cypress.Promise((resolve) => {
25+
if (win.getAllAngularTestabilities) {
26+
const testabilities = win.getAllAngularTestabilities()
27+
if (testabilities.length === 0) {
28+
resolve()
29+
return
30+
}
31+
let count = testabilities.length
32+
testabilities.forEach((testability: any) => {
33+
testability.whenStable(() => {
34+
count--
35+
if (count === 0) {
36+
resolve()
37+
}
38+
})
39+
})
40+
} else {
41+
resolve()
42+
}
43+
})
44+
})
45+
})
46+
47+
export {}

frontend/cypress/support/e2e.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import './commands'
2+
3+
// Hide fetch/XHR requests from command log
4+
Cypress.on('window:before:load', (win) => {
5+
cy.stub(win.console, 'log').as('consoleLog')
6+
cy.stub(win.console, 'error').as('consoleError')
7+
})

0 commit comments

Comments
 (0)