Skip to content

Commit

Permalink
Replacing Zombie JS with Puppeteer, remove mocha in favour of jest
Browse files Browse the repository at this point in the history
  • Loading branch information
Tom Rosier authored and paroxp committed Jul 12, 2021
1 parent c2ecee4 commit 4c9023f
Show file tree
Hide file tree
Showing 6 changed files with 1,861 additions and 1,840 deletions.
3 changes: 2 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
"SharedArrayBuffer": "readonly"
},
"ignorePatterns": [
"acceptance-tests/",
"config/",
"coverage/",
"dist/",
Expand Down Expand Up @@ -92,12 +91,14 @@
"overrides": [
{
"files": [
"acceptance-tests/**/*.test.{ts,tsx,js,jsx}",
"src/**/*.test.{ts,tsx,js,jsx}",
"stub-api/**/*.{ts,tsx,js,jsx}"
],
"rules": {
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-floating-promises": "off",
"@typescript-eslint/no-non-null-assertion": "off",
"functional/functional-parameters": "off",
"functional/no-let": "off",
Expand Down
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,21 @@ Execute the unit tests to ensure everything looks good:
npm test
```

Executing the acceptance tests against dev environment:

```sh
export PAAS_ADMIN_BASE_URL=https://admin.${DEPLOY_ENV}.dev.cloudpipeline.digital
export CF_API_BASE_URL=https://api.${DEPLOY_ENV}.dev.cloudpipeline.digital
export ACCOUNTS_API_BASE_URL=https://accounts.${DEPLOY_ENV}.dev.cloudpipeline.digital
export ACCOUNTS_USERNAME=admin
export ACCOUNTS_PASSWORD= # get this value from credhub using `credhub get -n /concourse/main/create-cloudfoundry/paas_accounts_password`

export ADMIN_USERNAME=admin
export ADMIN_PASSWORD= # get this value from credhub using `credhub get -n /${DEPLOY_ENV}/${DEPLOY_ENV}/cf_admin_password`

npm run test:acceptance
```

Start the server pointing at stubbed APIs

```sh
Expand Down
11 changes: 11 additions & 0 deletions acceptance-tests/jest-config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"testEnvironment": "node",
"moduleFileExtensions": [
"ts",
"js",
"json"
],
"testMatch": [
"<rootDir>/acceptance-tests/**/*.test.+(ts|tsx|js|jsx)"
]
}
102 changes: 63 additions & 39 deletions acceptance-tests/main.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import axios from 'axios';
import expect from 'expect';
import { after,before,describe,it } from 'mocha';
import puppeteer_expect from 'expect-puppeteer';
import pino from 'pino';
import Browser from 'zombie';
import puppeteer from 'puppeteer';

import { AccountsClient } from '../src/lib/accounts';
import CloudFoundryClient from '../src/lib/cf/cf';
Expand All @@ -15,6 +15,7 @@ const {
ACCOUNTS_PASSWORD,
ADMIN_USERNAME,
ADMIN_PASSWORD,
HEADLESS,
} = process.env;
if (!PAAS_ADMIN_BASE_URL) { throw 'PAAS_ADMIN_BASE_URL environment variable not set'; }
if (!CF_API_BASE_URL) { throw 'CF_API_BASE_URL environment variable not set'; }
Expand All @@ -23,8 +24,9 @@ if (!ACCOUNTS_PASSWORD) { throw 'ACCOUNTS_PASSWORD environment variable not set'
if (!ADMIN_USERNAME) { throw 'ADMIN_USERNAME environment variable not set'; }
if (!ADMIN_PASSWORD) { throw 'ADMIN_PASSWORD environment variable not set'; }

describe('paas-admin', function () {
this.timeout(10000);
const DEFAULT_WAIT_TIME = 30000;

describe('paas-admin', () => {

describe('when the client is not authenticated', () => {
it('passes its healthcheck', async () => {
Expand All @@ -36,7 +38,7 @@ describe('paas-admin', function () {

it('redirects to the login service', async () => {
try {
await axios.request({ url: PAAS_ADMIN_BASE_URL, maxRedirects: 0 });
await axios.request({ maxRedirects: 0, url: PAAS_ADMIN_BASE_URL });
}
catch(rejection) {
expect(rejection.response.status).toEqual(302);
Expand All @@ -49,25 +51,29 @@ describe('paas-admin', function () {
const managerUserEmail = `CAT-paas-admin-acceptance-manager-${randomSuffix}@example.com`;
const managerUserPassword = `${Math.floor(Math.random()*1e12)}`;

const browser = new Browser();
const browser = puppeteer.launch({ headless: !HEADLESS ? true : HEADLESS == 'true' });
let page: puppeteer.Page;

let cfClient: CloudFoundryClient;
let uaaClient: UAAClient;
let managerUserGuid: string;

before(async () => {
beforeAll(async () => {
cfClient = new CloudFoundryClient({
apiEndpoint: CF_API_BASE_URL,
logger: pino({ level: 'silent' }),
});

const cfInfo = await cfClient.info();
const accessToken = await authenticateUser(cfInfo.authorization_endpoint, { username: ADMIN_USERNAME, password: ADMIN_PASSWORD });
const accessToken = await authenticateUser(cfInfo.authorization_endpoint, {
password: ADMIN_PASSWORD,
username: ADMIN_USERNAME,
});

uaaClient = new UAAClient({ apiEndpoint: cfInfo.authorization_endpoint, accessToken: accessToken });
uaaClient = new UAAClient({ accessToken: accessToken, apiEndpoint: cfInfo.authorization_endpoint });
cfClient = new CloudFoundryClient({
apiEndpoint: CF_API_BASE_URL,
accessToken: accessToken,
apiEndpoint: CF_API_BASE_URL,
logger: pino({ level: 'silent' }),
});

Expand All @@ -77,44 +83,50 @@ describe('paas-admin', function () {
// Accept all pending documents:
const accountsClient = new AccountsClient({
apiEndpoint: ACCOUNTS_API_BASE_URL,
secret: ACCOUNTS_PASSWORD,
logger: pino({ level: 'silent' }),
secret: ACCOUNTS_PASSWORD,
});
const pendingDocuments = await accountsClient.getPendingDocumentsForUserUUID(uaaUser.id);
await Promise.all(pendingDocuments.map(d => accountsClient.createAgreement(d.name, uaaUser.id)));
await Promise.all(pendingDocuments.map(async d => await accountsClient.createAgreement(d.name, uaaUser.id)));

managerUserGuid = uaaUser.id;
});

after(async () => {
afterAll(async () => {
if (managerUserGuid) {
await uaaClient.deleteUser(managerUserGuid);
await cfClient.deleteUser(managerUserGuid);
}
(await browser).close();
});

before(async () => {
await <any>browser.visit(PAAS_ADMIN_BASE_URL);
browser.assert.text('button', 'Continue with email and password sign in');
beforeAll(async () => {
page = await (await browser).newPage();

await <any>browser.fill('username', managerUserEmail);
await <any>browser.fill('password', managerUserPassword);
await <any>browser.pressButton('Continue with email and password sign in'); // two spaces important because of DOM textContent
browser.assert.text('a', /Sign out/);
});
await page.goto(PAAS_ADMIN_BASE_URL);

await puppeteer_expect(page).toFill('input[name=username]', managerUserEmail);
await puppeteer_expect(page).toFill('input[name=password]', managerUserPassword);
await puppeteer_expect(page).toClick('button', { text: /Continue/ });

await page.waitForNavigation();

await puppeteer_expect(page).toMatchElement('a',{ text: /Sign out/ });
}, DEFAULT_WAIT_TIME);

it('should show a count of orgs on the home page', async () => {
await <any>browser.visit(PAAS_ADMIN_BASE_URL);
browser.assert.text('p', /There are 0 organisations/);
});
await page.goto(PAAS_ADMIN_BASE_URL);
await puppeteer_expect(page).toMatchElement('p', { text: /There are 0 organisations/ });
}, DEFAULT_WAIT_TIME);

describe('when the user is an organisation manager', () => {
let orgGuid: string;
let developerUserGuid: string;
const orgName = `CAT-paas-admin-${randomSuffix}`;
const developerUserEmail = `CAT-paas-admin-acceptance-developer-${randomSuffix}@example.com`;
const developerPassword = `${Math.floor(Math.random() * 1e12)}`;

before(async () => {
beforeAll(async () => {
const quotaDefinitions = await cfClient.quotaDefinitions({ name: 'small' });
const quotaGuid = quotaDefinitions[0].metadata.guid;
const organisation = await cfClient.createOrganization({
Expand All @@ -124,30 +136,42 @@ describe('paas-admin', function () {
orgGuid = organisation.metadata.guid;
await cfClient.setOrganizationRole(orgGuid, managerUserGuid, 'managers', true);

const uaaUser = await uaaClient.createUser(developerUserEmail, `${Math.floor(Math.random() * 1e12)}`);
const uaaUser = await uaaClient.createUser(developerUserEmail, developerPassword);
await cfClient.createUser(uaaUser.id);
developerUserGuid = uaaUser.id;
});

after(async () => {
if (orgGuid) { await cfClient.deleteOrganization({ guid: orgGuid, recursive: true, async: false }); }
afterAll(async () => {
if (orgGuid) { await cfClient.deleteOrganization({ async: false, guid: orgGuid, recursive: true }); }
if (developerUserGuid) { await cfClient.deleteUser(developerUserGuid); }
});

it('should show a count of orgs on the home page', async () => {
await <any>browser.visit(PAAS_ADMIN_BASE_URL);
browser.assert.text('p', /There is 1 organisation/);
});
await page.goto(PAAS_ADMIN_BASE_URL);
await puppeteer_expect(page).toMatchElement('p', { text: /There is 1 organisation/ });
}, DEFAULT_WAIT_TIME);

it('should invite a user', async () => {
await <any>browser.visit(`${PAAS_ADMIN_BASE_URL}/organisations/${orgGuid}/users/invite`);
browser.assert.text('h1', /Invite a new team member/);
await <any>browser.fill('email', developerUserEmail);
await <any>browser.check(`org_roles[${orgGuid}][managers][desired]`);
await <any>browser.pressButton('Send invitation');
browser.assert.text('.govuk-panel__title', /New team member successfully invited/);
});
});
await page.goto(PAAS_ADMIN_BASE_URL);

await puppeteer_expect(page).toClick('a', { text: orgName });
await page.waitForNavigation();

await puppeteer_expect(page).toClick('a', { text: /View and manage team members/ });
await page.waitForNavigation();

await puppeteer_expect(page).toClick('a', { text: /Invite a new team member/ });
await page.waitForNavigation();

await puppeteer_expect(page).toFill('input[name=email]', developerUserEmail);
await puppeteer_expect(page).toClick('label', { text: /Billing manager/ });
await puppeteer_expect(page).toClick('button', { text: /Send invitation/ });
await page.waitForNavigation();

await puppeteer_expect(page).toMatchElement('.govuk-panel__title',{
text: /New team member successfully invited/,
});
}, DEFAULT_WAIT_TIME);
});
});
});
Loading

0 comments on commit 4c9023f

Please sign in to comment.