Skip to content

Commit

Permalink
Setup and config Cypress
Browse files Browse the repository at this point in the history
  • Loading branch information
cajieh committed Jan 23, 2023
1 parent 27428fb commit bc40696
Show file tree
Hide file tree
Showing 18 changed files with 1,369 additions and 53 deletions.
4 changes: 4 additions & 0 deletions .ci-operator.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
build_root_image:
name: release
namespace: openshift
tag: nodejs-10-rhel7
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
node_modules/
dist/
.devcontainer/dev.env
integration-tests/videos
integration-tests/screenshots
integration-tests/.DS_Store
.DS_Store
10 changes: 10 additions & 0 deletions install_helm.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/usr/bin/env bash

USE_SUDO="false"
HELM_INSTALL_DIR="/tmp"

curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
chmod 700 get_helm.sh
source get_helm.sh

rm -rf get_helm.sh
17 changes: 17 additions & 0 deletions integration-tests/.eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"env": {
"cypress/globals": true,
"node": true
},
"extends": ["../.eslintrc.yml", "plugin:cypress/recommended"],
"plugins": ["cypress"],
"rules": {
"no-console": "off",
"no-namespace": "off",
"no-redeclare": "off",
"promise/catch-or-return": "off",
"promise/no-nesting": "off",
"@typescript-eslint/no-var-requires":"off",
"@typescript-eslint/no-namespace":"off"
}
}
27 changes: 27 additions & 0 deletions integration-tests/cypress.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
const { defineConfig } = require('cypress');

module.exports = defineConfig({
viewportWidth: 1920,
viewportHeight: 1080,
screenshotsFolder: './integration-tests/screenshots',
videosFolder: './integration-tests/videos',
video: false,
reporter: '../../node_modules/cypress-multi-reporters',
reporterOptions: {
configFile: 'reporter-config.json',
},
fixturesFolder: 'fixtures',
defaultCommandTimeout: 30000,
retries: {
runMode: 1,
openMode: 0,
},
e2e: {
setupNodeEvents(on, config) {
return require('./plugins/index.ts')(on, config);
},
specPattern: 'tests/**/*.cy.{js,jsx,ts,tsx}',
supportFile: 'support/index.ts',
baseUrl: 'http://localhost:9000/',
},
});
5 changes: 5 additions & 0 deletions integration-tests/fixtures/example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "Using fixtures to represent data",
"email": "[email protected]",
"body": "Fixtures are a great way to mock data for responses to routes"
}
27 changes: 27 additions & 0 deletions integration-tests/plugins/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import * as wp from '@cypress/webpack-preprocessor';

module.exports = (on, config) => {
const options = {
webpackOptions: {
resolve: {
extensions: ['.ts', '.tsx', '.js'],
},
module: {
rules: [
{
test: /\.tsx?$/,
loader: 'ts-loader',
options: { happyPackMode: true, transpileOnly: true },
},
],
},
},
};
on('file:preprocessor', wp(options));
// `config` is the resolved Cypress config
config.baseUrl = `${
process.env.BRIDGE_BASE_ADDRESS || 'http://localhost:9000/'
}`;
config.env.BRIDGE_KUBEADMIN_PASSWORD = process.env.BRIDGE_KUBEADMIN_PASSWORD;
return config;
};
14 changes: 14 additions & 0 deletions integration-tests/reporter-config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"reporterEnabled": "mocha-junit-reporter, mochawesome",
"mochaJunitReporterReporterOptions": {
"mochaFile": "./screenshots/junit_cypress-[hash].xml",
"toConsole": false
},
"mochawesomeReporterOptions": {
"reportDir": "./screenshots/",
"reportFilename": "cypress_report",
"overwrite": false,
"html": false,
"json": true
}
}
7 changes: 7 additions & 0 deletions integration-tests/support/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Import commands.js using ES2015 syntax:
import './login';

export const checkErrors = () =>
cy.window().then((win: any) => {
assert.isTrue(!win.windowError, win.windowError);
});
56 changes: 56 additions & 0 deletions integration-tests/support/login.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { submitButton } from '../views/form';
import { masthead } from '../views/masthead';

declare global {
namespace Cypress {
interface Chainable {
login(
providerName?: string,
username?: string,
password?: string,
): Chainable<Element>;
logout(): Chainable<Element>;
}
}
}

const KUBEADMIN_USERNAME = 'kubeadmin';

// any command added below, must be added to global Cypress interface above

// This will add 'cy.login(...)'
// ex: cy.login('my-idp', 'my-user', 'my-password')
Cypress.Commands.add(
'login',
(provider: string, username: string, password: string) => {
// Check if auth is disabled (for a local development environment).
cy.visit('http://localhost:9000/dashboards'); // visits baseUrl which is set in plugins/index.js
cy.window().then((win: any) => {
if (win.SERVER_FLAGS?.authDisabled) {
return;
}

// Make sure we clear the cookie in case a previous test failed to logout.
cy.clearCookie('openshift-session-token');

cy.get('#inputUsername').type(username || KUBEADMIN_USERNAME);
cy.get('#inputPassword').type(
password || Cypress.env('BRIDGE_KUBEADMIN_PASSWORD'),
);
cy.get(submitButton).click();
masthead.username.shouldBeVisible();
});
},
);

Cypress.Commands.add('logout', () => {
// Check if auth is disabled (for a local development environment).
cy.window().then((win: any) => {
if (win.SERVER_FLAGS?.authDisabled) {
return;
}
cy.get('[data-test="user-dropdown"]').click();
cy.get('[data-test="log-out"]').should('be.visible');
cy.get('[data-test="log-out"]').click({ force: true });
});
});
82 changes: 82 additions & 0 deletions integration-tests/tests/example-page.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { checkErrors } from '../support';

const PLUGIN_TEMPLATE_NAME = 'console-plugin-template';
const PLUGIN_TEMPLATE_PULL_SPEC = Cypress.env('PLUGIN_TEMPLATE_PULL_SPEC');
export const isLocalDevEnvironment =
Cypress.config('baseUrl').includes('localhost');

const installHelmChart = (path: string) => {
cy.exec(
`cd ../../console-plugin-template && ${path} upgrade -i ${PLUGIN_TEMPLATE_NAME} charts/openshift-console-plugin -n ${PLUGIN_TEMPLATE_NAME} --create-namespace --set plugin.image=${PLUGIN_TEMPLATE_PULL_SPEC}`,
{
failOnNonZeroExit: false,
},
).then((result: any) => {
cy.visit(`/example`);
cy.log('Error installing helm chart: ', result.stderr);
cy.log('Successfully installed helm chart: ', result.stdout);
});
};

const deleteHelmChart = (path: string) => {
cy.exec(
`cd ../../console-plugin-template && ${path} uninstall ${PLUGIN_TEMPLATE_NAME} -n ${PLUGIN_TEMPLATE_NAME} && oc delete namespaces ${PLUGIN_TEMPLATE_NAME}`,
{
failOnNonZeroExit: false,
},
).then((result: any) => {
cy.log('Error uninstalling helm chart: ', result.stderr);
cy.log('Successfully uninstalled helm chart: ', result.stdout);
});
};

if (!Cypress.env('OPENSHIFT_CI') || Cypress.env('PLUGIN_TEMPLATE_PULL_SPEC')) {
describe('Console plugin template test', () => {
before(() => {
cy.login();

if (!isLocalDevEnvironment) {
console.log('this is not a local env, installig helm');

cy.exec('cd ../../console-plugin-template && ./install_helm.sh', {
failOnNonZeroExit: false,
}).then((result) => {
cy.log('Error installing helm binary: ', result.stderr);
cy.log(
'Successfully installed helm binary in "/tmp" directory: ',
result.stdout,
);

installHelmChart('/tmp/helm');
});
} else {
console.log('this is a local env, not installing helm');

installHelmChart('helm');
}
});

afterEach(() => {
checkErrors();
});

after(() => {
cy.logout();
if (!isLocalDevEnvironment) {
deleteHelmChart('/tmp/helm');
} else {
deleteHelmChart('helm');
}
});

it('Verify the url', () => {
cy.url().should('include', '/example');
});
it('Verify the example page title', () => {
cy.get('[data-test="example-page-title"]').should(
'contain',
'Hello, Plugin!',
);
});
});
}
9 changes: 9 additions & 0 deletions integration-tests/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"noEmit": true,
"types":["cypress","node"],
"isolatedModules": false
},
"include": ["../node_modules/cypress", "./**/*.ts"]
}
1 change: 1 addition & 0 deletions integration-tests/views/form.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const submitButton = 'button[type=submit]';
23 changes: 23 additions & 0 deletions integration-tests/views/masthead.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
export const masthead = {
username: {
shouldBeVisible: () =>
cy
.get(
`[data-test=${Cypress.env(
'BRIDGE_KUBEADMIN_PASSWORD',
)} ? 'user-dropdown' : 'username'`,
)
.should('be.visible'),
shouldHaveText: (text: string) =>
cy
.get(
`[data-test=${Cypress.env(
'BRIDGE_KUBEADMIN_PASSWORD',
)} ? 'user-dropdown' : 'username'`,
)
.should('have.text', text),
},
clickMastheadLink: (path: string) => {
return cy.get(`[data-test=${path}`).click();
},
};
10 changes: 9 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,12 @@
"start-console": "./start-console.sh",
"i18n": "i18next \"src/**/*.{js,jsx,ts,tsx}\" [-oc] -c i18next-parser.config.js",
"ts-node": "ts-node -O '{\"module\":\"commonjs\"}'",
"lint": "eslint ./src --fix && stylelint \"src/**/*.css\" --allow-empty-input --fix"
"lint": "eslint ./src ./integration-tests --fix && stylelint \"src/**/*.css\" --allow-empty-input --fix",
"test-cypress": "cd integration-tests s && cypress open --env openshift=true",
"test-cypress-headless": "cd integration-tests && node --max-old-space-size=4096 ../node_modules/.bin/cypress run --env openshift=true --browser ${BRIDGE_E2E_BROWSER_NAME:=chrome}"
},
"devDependencies": {
"@cypress/webpack-preprocessor": "^5.15.5",
"@openshift-console/dynamic-plugin-sdk": "0.0.12",
"@openshift-console/dynamic-plugin-sdk-webpack": "0.0.7",
"@patternfly/react-core": "4.221.3",
Expand All @@ -25,10 +28,15 @@
"@typescript-eslint/eslint-plugin": "^5.29.0",
"@typescript-eslint/parser": "^5.29.0",
"css-loader": "^6.7.1",
"cypress": "^11.0.1",
"cypress-multi-reporters": "^1.6.2",
"eslint": "^8.18.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-cypress": "^2.12.1",
"eslint-plugin-prettier": "^4.1.0",
"eslint-plugin-react": "^7.30.1",
"mocha-junit-reporter": "^2.2.0",
"mochawesome": "^7.1.3",
"prettier": "^2.7.1",
"prettier-stylelint": "^0.4.2",
"react": "^17.0.1",
Expand Down
2 changes: 1 addition & 1 deletion src/components/ExamplePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export default function ExamplePage() {
return (
<>
<Helmet>
<title>Hello, Plugin!</title>
<title data-test="example-page-title">Hello, Plugin!</title>
</Helmet>
<Page>
<PageSection variant="light">
Expand Down
28 changes: 28 additions & 0 deletions test-prow-e2e.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/usr/bin/env bash

set -exuo pipefail

ARTIFACT_DIR=${ARTIFACT_DIR:=/tmp/artifacts}
SCREENSHOTS_DIR=integration-tests/screenshots
INSTALLER_DIR=${INSTALLER_DIR:=${ARTIFACT_DIR}/installer}

function copyArtifacts {
if [ -d "$ARTIFACT_DIR" ] && [ -d "$SCREENSHOTS_DIR" ]; then
echo "Copying artifacts from $(pwd)..."
cp -r "$SCREENSHOTS_DIR" "${ARTIFACT_DIR}/integration-tests/screenshots"
fi
}


trap copyArtifacts EXIT

# don't log kubeadmin-password
set +x
BRIDGE_KUBEADMIN_PASSWORD="$(cat "${KUBEADMIN_PASSWORD_FILE:-${INSTALLER_DIR}/auth/kubeadmin-password}")"
export BRIDGE_KUBEADMIN_PASSWORD
set -x
BRIDGE_BASE_ADDRESS="$(oc get consoles.config.openshift.io cluster -o jsonpath='{.status.consoleURL}')"
export BRIDGE_BASE_ADDRESS

echo "Runs Cypress tests in headless mode"
yarn run test-cypress-headless
Loading

0 comments on commit bc40696

Please sign in to comment.