Skip to content

Commit

Permalink
Merge pull request #7 from dpc-sdp/feature/cypress-ci
Browse files Browse the repository at this point in the history
Adds Cypress and GitHub Actions CI config
  • Loading branch information
dylankelly authored Jul 27, 2023
2 parents e29f46d + 4cba616 commit 653e7c0
Show file tree
Hide file tree
Showing 18 changed files with 26,543 additions and 15 deletions.
23 changes: 23 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<!-- Add link to JIRA eg: https://digital-vic.atlassian.net/browse/SDPAP- or GitHub Issue Number eg: #123 -->

**Issue**:

### What I did
<!-- Summary of changes made in the Pull Request -->
-
-

### How to test
<!-- Summary of how to test -->
-
-

### Checklist
<!-- Go over all the following points, and put an `x` in all the boxes that apply. -->

- [ ] I have read the [Ripple documentation](https://www.ripple.sdp.vic.gov.au/framework/) documentation around adding custom functionality.
- [ ] I have added Cypress integration tests for new content types or components
- [ ] I have added unit tests for helper functions
- [ ] This PR requires changes to environment variables which need to be added in https://github.com/dpc-sdp/sdp-cmdb


36 changes: 26 additions & 10 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -1,18 +1,34 @@
name: build and test

on:
push:
branches: [ $default-branch ]
pull_request:
branches: [ $default-branch ]

name: Build & Test
on: [push]
jobs:
build:
Build-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 18
- run: npm ci
- name: Install Dependencies
run: npm ci
- run: npm run build
- run: npm run lint
- run: npm run test:unit

Integration:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Cypress run
uses: cypress-io/github-action@v5
env:
DEBUG: '@cypress/github-action'
NUXT_PUBLIC_TIDE_BASE_URL: 'https://develop.content.reference.sdp.vic.gov.au/'
NUXT_PUBLIC_TIDE_SITE: '8888'
NUXT_PUBLIC_API_URL: 'http://localhost:3001'
API_PORT: '3001'
with:
build: npm run build
start: npm start
wait-on: 'http://localhost:3000/api/tide/site?id=8888'

6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,16 @@ node_modules
nuxt.d.ts
.output
.env
package-lock.json
framework
dist
.DS_Store
coverage

# Cypress
cypress/downloads
cypress/screenshots
cypress/videos

# Local History
.history

Expand Down
8 changes: 8 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"endOfLine": "lf",
"semi": false,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "none",
"jsxSingleQuote": true
}
41 changes: 41 additions & 0 deletions cypress.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import 'dotenv/config'
import { defineConfig } from 'cypress'
import cucumberPreprocessor from '@badeball/cypress-cucumber-preprocessor'
import cucumberPreprocessorEsBuild from '@badeball/cypress-cucumber-preprocessor/esbuild'
import * as createBundlerDefault from '@bahmutov/cypress-esbuild-preprocessor'
import apiMocking from './cypress/support/mockttp'
const testFolder = './cypress'
const { addCucumberPreprocessorPlugin } = cucumberPreprocessor

export default defineConfig({
env: {
searchIndex: process.env.NUXT_PUBLIC_TIDE_APP_SEARCH_ENGINE_NAME
},
e2e: {
baseUrl: 'http://localhost:3000',
specPattern: '**/*.{feature,feature.ts}',
supportFile: `${testFolder}/support/index.ts`,
supportFolder: testFolder,
downloadsFolder: `${testFolder}/downloads`,
fixturesFolder: `${testFolder}/fixtures`,
videosFolder: `${testFolder}/videos`,
screenshotsFolder: `${testFolder}/screenshots`,
async setupNodeEvents (
on: Cypress.PluginEvents,
config: Cypress.PluginConfigOptions
): Promise<Cypress.PluginConfigOptions> {
await addCucumberPreprocessorPlugin(on, config)
const createBundler = createBundlerDefault.default
on(
'file:preprocessor',
createBundler({
plugins: [cucumberPreprocessorEsBuild.createEsbuildPlugin(config)]
})
)
on('task', { ...apiMocking })

return config
}
},
blockHosts: ['*youtube.com', '*doubleclick.net']
})
Empty file added cypress/e2e/.gitkeep
Empty file.
7 changes: 7 additions & 0 deletions cypress/e2e/example.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Feature: Example test

This is an example test which should be modified or removed as required. See @dpc-sdp/ripple-test-utils for more info.

@mockserver @skip
Scenario: Example - delete me.
Given I visit the page "/"
Empty file added cypress/fixtures/.gitkeep
Empty file.
38 changes: 38 additions & 0 deletions cypress/support/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/// <reference types="cypress" />

// ***********************************************
// This example commands.ts shows you how to
// create various custom commands and overwrite
// existing commands.
//
// For more comprehensive examples of custom
// commands please read more here:
// https://on.cypress.io/custom-commands
// ***********************************************
//
//
// -- This is a parent command --
// Cypress.Commands.add('login', (email, password) => { ... })
//
//
// -- This is a child command --
// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
//
//
// -- This is a dual command --
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
//
//
// -- This will overwrite an existing command --
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
//
// declare global {
// namespace Cypress {
// interface Chainable {
// login(email: string, password: string): Chainable<void>
// drag(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
// dismiss(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
// visit(originalFn: CommandOriginalFn, url: string, options: Partial<VisitOptions>): Chainable<Element>
// }
// }
// }
56 changes: 56 additions & 0 deletions cypress/support/mockttp.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/* eslint-disable no-console */
import { getLocal } from 'mockttp'
const mockServer = getLocal({ cors: true })

export default {
async startMockServer (proxy = false) {
const port = 3001
try {
if (mockServer.url) {
await mockServer.stop()
await mockServer.start(port)
console.log(`Mock server running at : ${mockServer.url}`)
}
} catch (error) {
await mockServer.start(port)
}
if (proxy) {
mockServer.forAnyRequest().thenForwardTo('http://localhost:3000')
}
return mockServer.url
},
async stopMockServer () {
try {
await mockServer.stop()
return true
} catch (error) {
return false
}
},
async setMockRoute ({ route, status, response }) {
const endpointMock = await mockServer
.forGet(route)
.thenJson(status, response)

return endpointMock
},
async setMockRouteWithQuery ({ route, status, response, query }) {
const endpointMock = await mockServer
.forGet(route)
.withExactQuery(query)
.thenJson(status, response)
return endpointMock
},

async setMockPostRouteWithQuery ({ route, status, response, query }) {
const endpointMock = await mockServer
.forPost(route)
.withExactQuery(query)
.thenJson(status, response, {
'access-control-allow-origin': '*',
'access-control-allow-headers': '*',
'access-control-allow-methods': '*'
})
return endpointMock
}
}
1 change: 1 addition & 0 deletions cypress/support/step_definitions/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import '@dpc-sdp/ripple-test-utils/step_definitions'
6 changes: 6 additions & 0 deletions mock-routes.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[
{
"path": "/",
"fixture": "demo/demo.json"
}
]
39 changes: 39 additions & 0 deletions mockserver.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import mockttp from 'mockttp'
import mockedRoutes from './mock-routes.json' assert { type: 'json' }
import mockSiteTaxonomy from './cypress/fixtures/site/reference.json' assert { type: 'json' }

const mockServer = mockttp.getLocal()

const setupMockServer = async () => {
const API_URL = parseInt(process.env.API_URL) || 3001
await mockServer.start(API_URL)

console.log('starting mock server...', mockServer.url)

console.log(`Mocking site data: ${mockServer.url}/api/tide/site?id=8888`)
await mockServer
.forGet('/api/tide/site')
.always()
.withExactQuery(`?id=8888`)
.thenJson(200, mockSiteTaxonomy)

for (let index = 0; index < mockedRoutes.length; index++) {
const route = mockedRoutes[index]
console.log(
`Mocking route : ${mockServer.url}/api/tide/page?path=${route.path}&site=8888`
)
const fixture = await import(`./cypress/fixtures/${route.fixture}`, {
assert: { type: 'json' }
}).then((mdl) => mdl.default)
console.log(fixture)
await mockServer
.forGet('/api/tide/page')
.always()
.withExactQuery(`?path=${route.path}&site=8888`)
.thenJson(200, fixture)
}

await mockServer.forAnyRequest().thenForwardTo('http://localhost:3000')
}

setupMockServer()
Loading

0 comments on commit 653e7c0

Please sign in to comment.