Skip to content

Commit

Permalink
Merge pull request #2313 from concord-consortium/187652818-cypress-on…
Browse files Browse the repository at this point in the history
…-staging

workflow to run cypress against deployed paths
  • Loading branch information
scytacki committed May 31, 2024
2 parents d133a3e + a239164 commit af3fda0
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 21 deletions.
67 changes: 67 additions & 0 deletions .github/workflows/deployed-regresssion.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
name: Deployed Regression

on:
workflow_dispatch:
inputs:
branch:
description: Branch containing cypress tests
default: master
required: true
deployedPath:
description: Path to test. It is added to https://collaborative-learning.concord.org/
default: branch/master
required: true
jobs:
all-tests:
runs-on: ubuntu-latest
container:
image: cypress/browsers:node-20.11.0-chrome-121.0.6167.184-1-ff-123.0-edge-121.0.2277.128-1
# This is needed so the commit info can be recorded by cypress
options: --user 1001
strategy:
# when one test fails, DO NOT cancel the other
# containers, because this will kill Cypress processes
# leaving the Dashboard hanging ...
# https://github.com/cypress-io/github-action/issues/48
fail-fast: false
matrix:
# run 5 copies of the current job in parallel
containers: [1, 2, 3, 4, 5, 6, 7]
steps:
- name: Checkout Repository
uses: actions/checkout@v4
with:
ref: ${{ github.event.inputs.branch }}
# Hard code the branch for testing
# ref: 187652818-cypress-on-staging
- name: Run Cypress Tests
uses: cypress-io/github-action@v6
with:
# TODO: we might need to manual set the build id
# TODO: the description of the run in cypress will be the commit message of branch
# instead of something about the app being tested. This can be overriden using these
# env variables: https://docs.cypress.io/guides/continuous-integration/introduction#Git-information

# only record the results to dashboard.cypress.io if CYPRESS_RECORD_KEY is set
record: ${{ !!secrets.CYPRESS_RECORD_KEY }}
# only do parallel if we have a record key
parallel: ${{ !!secrets.CYPRESS_RECORD_KEY }}
browser: chrome
spec: cypress/e2e/functional/**
# We can't use index-staging.html for several reasons:
# - visiting the doc-editor won't work with that baseUrl
# - loading the qa units won't work without additional changes because
# they would be relative to the root instead of the version folder
config: baseUrl=https://collaborative-learning.concord.org/${{ github.event.inputs.deployedPath }}/
# Hard code the baseUrl for testing
# config: baseUrl=https://collaborative-learning.concord.org/version/v5.10.1/
env:
# pass the Dashboard record key as an environment variable
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
# pass GitHub token to allow accurately detecting a build vs a re-run build
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Increase memory allocation
NODE_OPTIONS: "--max_old_space_size=4096"

# Note: we can't do code coverage because the deployed code will not be
# instrumented
36 changes: 22 additions & 14 deletions cypress.config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { defineConfig } from 'cypress';
import fs from 'fs-extra';
import path from 'path';
import installLogsPrinter from 'cypress-terminal-report/src/installLogsPrinter';
import codeCoverageTask from '@cypress/code-coverage/task';

export default defineConfig({
video: false,
Expand Down Expand Up @@ -42,23 +44,29 @@ export default defineConfig({
numTestsKeptInMemory: 10,
experimentalRunAllSpecs: true,
experimentalMemoryManagement: true,
setupNodeEvents(on, config) {
const fetchConfigurationByFile = file => {
const pathOfConfigurationFile = `config/cypress.${file}.json`;
async setupNodeEvents(on, config) {
console.log("Cypress config", {baseUrl: config.baseUrl, testEnv: config.env.testEnv});

return (
file && fs.readJson(path.join(__dirname, "./cypress/", pathOfConfigurationFile))
);
};
// Print out cypress log to the command line so it is recorded by the CI system
installLogsPrinter(on);

require('cypress-terminal-report/src/installLogsPrinter')(on);
function getEnvConfig() {
const testEnv = config.env.testEnv;
if (testEnv) {
const pathOfConfigurationFile = `config/cypress.${testEnv}.json`;
return fs.readJson(path.join(__dirname, "./cypress/", pathOfConfigurationFile));
} else {
return {};
}
}
const envConfig = await getEnvConfig();
const combinedConfig = { ...config, ...envConfig };

const environment = config.env.testEnv || 'dev';
// First, read environments.json.
return fetchConfigurationByFile(environment)
.then(envConfig => {
return require('@cypress/code-coverage/task')(on, { ...config, ...envConfig });
});
// Save the code coverage information after each test.
// This also modifies the combinedConfig so the modified config needs to be returned
codeCoverageTask(on, combinedConfig);

return combinedConfig;
},
baseUrl: 'http://localhost:8080/',
specPattern: 'cypress/e2e/**/*.{js,jsx,ts,tsx}',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ function setupTest(studentIndex) {

context('Test group functionalities', function () {
it('4-up view read-only', function () {

cy.log('students to check each others tiles in 4-up view read-only');
cy.clearQAData('all');

Expand Down
2 changes: 1 addition & 1 deletion cypress/e2e/functional/document_tests/group_test_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ let qaGroup = 10,
students = [15, 16, 17, 18, 19];

function getUrl(studentIndex) {
return `/?appMode=qa&qaGroup=10&fakeClass=10&problem=1.1&fakeUser=student:${students[studentIndex]}&unit=./demo/units/qa/content.json`
return `/?appMode=qa&qaGroup=10&fakeClass=10&problem=1.1&fakeUser=student:${students[studentIndex]}&unit=./demo/units/qa/content.json`;
}

function setupTest(studentIndex) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ describe('SortWorkView Tests', () => {
});

cy.log("verify that exemplar document shows in Sort Work");
sortWork.getSortWorkItem().eq(0).should('contain', exemplarDocs[0]);
sortWork.getSortWorkItem().should('contain', exemplarDocs[0]);

cy.log("open problem doc and make sure Edit button doesn't show and Close button shows");
sortWork.getSortWorkItem().contains(studentProblemDocs[0]).click();
Expand Down
8 changes: 4 additions & 4 deletions docs/cypress-coverage.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ The first step in the process is tracking which lines of code are hit. This is d
- look in the browser console for `window.__coverage__`
- this variable should contain info about each file that has been covered so far

This coverage information needs to be collected after each test run. This is done by the `@cypress/code-coverage/support` module that is imported in the `cypress/support/index.js` file. It sets up the coverage stats before each test, and then sends the coverage information to the cypress test runner via `cy.task`.
This coverage information needs to be collected after each test run. This is done by the `@cypress/code-coverage/support` module that is imported in the `cypress/support/e2e.js` file. It sets up the coverage stats before each test, and then sends the coverage information to the cypress test runner via `cy.task`.

The coverage information needs to be received by the cypress test runner and written out to a file. This is done by the plugin `@cypress/code-coverage/task`. It is added to the `cypress/plugins/index.js`. It receives the coverage information, merges it and saves it in the raw file `.nyc_output/out.json`. It also defines a task command which runs the nyc processor to convert this raw file into a set of html files.
The coverage information needs to be received by the cypress test runner and written out to a file. This is done by the plugin `@cypress/code-coverage/task`. It is added by `cypress.config.ts`. It receives the coverage information, merges it and saves it in the raw file `.nyc_output/out.json`. It also defines a task command which runs the nyc processor to convert this raw file into a set of html files.

By default the cypress coverage tasks are disabled so they don't slow down and clutter up the test log. You can open cypress with them enabled by using the `npm run test:coverage:cypress:open`. For reference, the default behavior is set in `cypress.jon` with the `"coverage": false` entry.
By default the cypress coverage tasks are disabled so they don't slow down and clutter up the test log. You can open cypress with them enabled by using the `npm run test:coverage:cypress:open`. For reference, the default behavior is set in `cypress.config.ts` with the `coverage: false` entry.

With the coverage tasks enabled, when running the cypress tests you should see extra 'task' events being logged. These are a record of the `support` module communicating with the `task` module.

Expand All @@ -28,4 +28,4 @@ The nyc processor is configured by the `nyc` section in `package.json`. It is co

This setup hasn't been tested to see if it covers cypress based unit tests. These work slightly differently because in this case the application code is imported right into the test runner code. So in this case the test runner needs to instrument this application code when it is loaded.

In theory the setup in this project should work in this case. This is because the `@cypress/webpack-preprocessor` is being used. This should pass all cypress test code through the same webpack config that is used by the webpack-dev-server. So the application code should get instrumented during this process by the `istanbul-instrumenter-loader`.
In theory the setup in this project should work in this case. This is because the `@cypress/webpack-preprocessor` is being used. This should pass all cypress test code through the same webpack config that is used by the webpack-dev-server. So the application code should get instrumented during this process by the `istanbul-instrumenter-loader`.

0 comments on commit af3fda0

Please sign in to comment.