-
Notifications
You must be signed in to change notification settings - Fork 67
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Griffin-Sullivan <gsulliva@redhat.com>
- Loading branch information
1 parent
bda3731
commit 3fdebb0
Showing
16 changed files
with
11,966 additions
and
6,273 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
# Test against prod build hosted by lightweight http server | ||
BASE_URL=http://localhost:9001 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
# Model Registry UI Testing | ||
|
||
## Cypress Tests | ||
|
||
Cypress is used to run tests against the frontend while mocking all network requests. | ||
|
||
Single command to run all Cypress tests or a specific test (build frontend, start HTTP server, run Cypress): | ||
```bash | ||
npm run test:cypress-ci | ||
|
||
npm run test:cypress-ci -- --spec "**/testfile.cy.ts" | ||
``` | ||
|
||
Cypress tests require a frontend server to be running. | ||
|
||
To best match production, build the frontend and use a lightweight HTTP server to host the files. This method will require manual rebuilds when changes are made to the dashboard frontend code. | ||
```bash | ||
npm run cypress:server:build | ||
npm run cypress:server | ||
``` | ||
|
||
To run all Cypress tests or a specific test headless | ||
```bash | ||
npm run cypress:run:mock | ||
|
||
npm run cypress:run:mock -- --spec "**/testfile.cy.ts" | ||
``` |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
coverage | ||
results |
122 changes: 122 additions & 0 deletions
122
clients/ui/frontend/src/__tests__/cypress/cypress.config.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
import path from 'path'; | ||
import fs from 'fs'; | ||
import { defineConfig } from 'cypress'; | ||
import coverage from '@cypress/code-coverage/task'; | ||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment | ||
// @ts-ignore no types available | ||
import cypressHighResolution from 'cypress-high-resolution'; | ||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment | ||
// @ts-ignore no types available | ||
import { beforeRunHook, afterRunHook } from 'cypress-mochawesome-reporter/lib'; | ||
import { mergeFiles } from 'junit-report-merger'; | ||
import { env, BASE_URL } from '~/src/__tests__/cypress/cypress/utils/testConfig'; | ||
|
||
|
||
const resultsDir = `${env.CY_RESULTS_DIR || 'results'}/${env.CY_MOCK ? 'mocked' : 'e2e'}`; | ||
|
||
export default defineConfig({ | ||
experimentalMemoryManagement: true, | ||
// Use relative path as a workaround to https://github.com/cypress-io/cypress/issues/6406 | ||
reporter: '../../../node_modules/cypress-multi-reporters', | ||
reporterOptions: { | ||
reporterEnabled: 'cypress-mochawesome-reporter, mocha-junit-reporter', | ||
mochaJunitReporterReporterOptions: { | ||
mochaFile: `${resultsDir}/junit/junit-[hash].xml`, | ||
}, | ||
cypressMochawesomeReporterReporterOptions: { | ||
charts: true, | ||
embeddedScreenshots: false, | ||
ignoreVideos: false, | ||
inlineAssets: true, | ||
reportDir: resultsDir, | ||
videoOnFailOnly: true, | ||
}, | ||
}, | ||
chromeWebSecurity: false, | ||
viewportWidth: 1920, | ||
viewportHeight: 1080, | ||
numTestsKeptInMemory: 1, | ||
video: true, | ||
screenshotsFolder: `${resultsDir}/screenshots`, | ||
videosFolder: `${resultsDir}/videos`, | ||
env: { | ||
MOCK: !!env.CY_MOCK, | ||
coverage: !!env.CY_COVERAGE, | ||
codeCoverage: { | ||
exclude: [path.resolve(__dirname, '../../third_party/**')], | ||
}, | ||
resolution: 'high', | ||
}, | ||
defaultCommandTimeout: 10000, | ||
e2e: { | ||
baseUrl: BASE_URL, | ||
specPattern: env.CY_MOCK | ||
? `cypress/tests/mocked/**/*.cy.ts` | ||
: `cypress/tests/e2e/**/*.cy.ts`, | ||
experimentalInteractiveRunEvents: true, | ||
setupNodeEvents(on, config) { | ||
cypressHighResolution(on, config); | ||
coverage(on, config); | ||
on('task', { | ||
readJSON(filePath: string) { | ||
const absPath = path.resolve(__dirname, filePath); | ||
if (fs.existsSync(absPath)) { | ||
try { | ||
return Promise.resolve(JSON.parse(fs.readFileSync(absPath, 'utf8'))); | ||
} catch { | ||
// return default value | ||
} | ||
} | ||
|
||
return Promise.resolve({}); | ||
}, | ||
log(message) { | ||
// eslint-disable-next-line no-console | ||
console.log(message); | ||
return null; | ||
}, | ||
error(message) { | ||
// eslint-disable-next-line no-console | ||
console.error(message); | ||
return null; | ||
}, | ||
table(message) { | ||
// eslint-disable-next-line no-console | ||
console.table(message); | ||
return null; | ||
}, | ||
}); | ||
|
||
// Delete videos for specs without failing or retried tests | ||
on('after:spec', (_, results) => { | ||
if (results.video) { | ||
// Do we have failures for any retry attempts? | ||
const failures = results.tests.some((test) => | ||
test.attempts.some((attempt) => attempt.state === 'failed'), | ||
); | ||
if (!failures) { | ||
// delete the video if the spec passed and no tests retried | ||
fs.unlinkSync(results.video); | ||
} | ||
} | ||
}); | ||
|
||
on('before:run', async (details) => { | ||
// cypress-mochawesome-reporter | ||
await beforeRunHook(details); | ||
}); | ||
|
||
on('after:run', async () => { | ||
// cypress-mochawesome-reporter | ||
await afterRunHook(); | ||
|
||
// merge junit reports into a single report | ||
const outputFile = path.join(__dirname, resultsDir, 'junit-report.xml'); | ||
const inputFiles = [`./${resultsDir}/junit/*.xml`]; | ||
await mergeFiles(outputFile, inputFiles); | ||
}); | ||
|
||
return config; | ||
}, | ||
}, | ||
}); |
11 changes: 11 additions & 0 deletions
11
clients/ui/frontend/src/__tests__/cypress/cypress/pages/home.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
class Home { | ||
visit() { | ||
cy.visit(`/`); | ||
} | ||
|
||
findButton() { | ||
return cy.get('button:contains("Primary Action")'); | ||
} | ||
} | ||
|
||
export const home = new Home(); |
17 changes: 17 additions & 0 deletions
17
clients/ui/frontend/src/__tests__/cypress/cypress/pages/pageNoteFound.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
class PageNotFound { | ||
visit() { | ||
cy.visit(`/force-not-found-page`, {'failOnStatusCode': false}); | ||
this.wait(); | ||
} | ||
|
||
private wait() { | ||
this.findPage(); | ||
cy.testA11y(); | ||
} | ||
|
||
findPage() { | ||
return cy.get('h1:contains("404 Page not found")'); | ||
} | ||
} | ||
|
||
export const pageNotfound = new PageNotFound(); |
68 changes: 68 additions & 0 deletions
68
clients/ui/frontend/src/__tests__/cypress/cypress/support/commands/axe.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import 'cypress-axe'; | ||
|
||
/* eslint-disable @typescript-eslint/no-namespace */ | ||
declare global { | ||
namespace Cypress { | ||
interface Chainable { | ||
testA11y: (context?: Parameters<cy['checkA11y']>[0]) => void; | ||
} | ||
} | ||
} | ||
|
||
Cypress.Commands.add('testA11y', { prevSubject: 'optional' }, (subject, context) => { | ||
const test = (c: Parameters<typeof cy.checkA11y>[0]) => { | ||
cy.window({ log: false }).then((win) => { | ||
// inject on demand | ||
if (!(win as { axe: unknown }).axe) { | ||
cy.injectAxe(); | ||
} | ||
cy.checkA11y( | ||
c, | ||
{ | ||
includedImpacts: ['serious', 'critical'], | ||
}, | ||
(violations) => { | ||
cy.task( | ||
'error', | ||
`${violations.length} accessibility violation${violations.length === 1 ? '' : 's'} ${ | ||
violations.length === 1 ? 'was' : 'were' | ||
} detected`, | ||
); | ||
// pluck specific keys to keep the table readable | ||
const violationData = violations.map(({ id, impact, description, nodes }) => ({ | ||
id, | ||
impact, | ||
description, | ||
nodes: nodes.length, | ||
})); | ||
|
||
cy.task('table', violationData); | ||
|
||
cy.task( | ||
'log', | ||
violations | ||
.map( | ||
({ nodes }, i) => | ||
`${i}. Affected elements:\n${nodes.map( | ||
({ target, failureSummary, ancestry }) => | ||
`\t${failureSummary} - ${target | ||
.map((node) => `"${node}"\n${ancestry}`) | ||
.join(', ')}`, | ||
)}`, | ||
) | ||
.join('\n'), | ||
); | ||
}, | ||
); | ||
}); | ||
}; | ||
if (!context && subject) { | ||
cy.wrap(subject).each(($el) => { | ||
Cypress.log({ displayName: 'testA11y', $el }); | ||
test($el[0]); | ||
}); | ||
} else { | ||
Cypress.log({ displayName: 'testA11y' }); | ||
test(context); | ||
} | ||
}); |
2 changes: 2 additions & 0 deletions
2
clients/ui/frontend/src/__tests__/cypress/cypress/support/commands/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
import '@testing-library/cypress/add-commands'; | ||
import './axe'; |
34 changes: 34 additions & 0 deletions
34
clients/ui/frontend/src/__tests__/cypress/cypress/support/e2e.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
// *********************************************************** | ||
// This example support/e2e.ts is processed and | ||
// loaded automatically before your test files. | ||
// | ||
// This is a great place to put global configuration and | ||
// behavior that modifies Cypress. | ||
// | ||
// You can change the location of this file or turn off | ||
// automatically serving support files with the | ||
// 'supportFile' configuration option. | ||
// | ||
// You can read more here: | ||
// https://on.cypress.io/configuration | ||
// *********************************************************** | ||
|
||
import chaiSubset from 'chai-subset'; | ||
import '@cypress/code-coverage/support'; | ||
import 'cypress-mochawesome-reporter/register'; | ||
import './commands'; | ||
|
||
chai.use(chaiSubset); | ||
|
||
|
||
Cypress.Keyboard.defaults({ | ||
keystrokeDelay: 0, | ||
}); | ||
|
||
beforeEach(() => { | ||
if (Cypress.env('MOCK')) { | ||
// fallback: return 404 for all api requests | ||
cy.intercept({ pathname: '/api/**' }, { statusCode: 404 }); | ||
|
||
} | ||
}); |
15 changes: 15 additions & 0 deletions
15
clients/ui/frontend/src/__tests__/cypress/cypress/tests/mocked/application.cy.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import { pageNotfound } from "~/src/__tests__/cypress/cypress/pages/pageNoteFound"; | ||
import { home } from "~/src/__tests__/cypress/cypress/pages/home"; | ||
|
||
describe('Application', () => { | ||
|
||
it('Page not found should render', () => { | ||
pageNotfound.visit() | ||
}); | ||
|
||
it('Home page should have primary button', () => { | ||
home.visit() | ||
home.findButton(); | ||
}); | ||
|
||
}); |
19 changes: 19 additions & 0 deletions
19
clients/ui/frontend/src/__tests__/cypress/cypress/utils/testConfig.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import path from 'path'; | ||
import { env } from 'process'; | ||
import dotenv from 'dotenv'; | ||
|
||
[ | ||
`.env.cypress${env.CY_MOCK ? '.mock' : ''}.local`, | ||
`.env.cypress${env.CY_MOCK ? '.mock' : ''}`, | ||
'.env.local', | ||
'.env', | ||
].forEach((file) => | ||
dotenv.config({ | ||
path: path.resolve(__dirname, '../../../../../', file), | ||
}), | ||
); | ||
|
||
export const BASE_URL = env.BASE_URL || ''; | ||
|
||
// re-export the updated process env | ||
export { env }; |
Oops, something went wrong.