Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/dispatch_internal_repo_workflow.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ jobs:
break
fi

echo $in_progress
echo "Waiting for workflow to start..."
sleep 15
done
Expand Down
4 changes: 4 additions & 0 deletions tests/security/config/playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ export default defineConfig({
slowMo: 0,
},
video: 'on',
viewport: {
height: 1200,
width: 1600,
},
headless: true,
},
},
Expand Down
23 changes: 15 additions & 8 deletions tests/security/functions/common-steps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,14 @@ export async function createEmailTemplate(
'/templates/create-email-template'
);

await page.waitForLoadState('load');
await expect(page.getByTestId('navigation-links')).toBeVisible();

await page.getByLabel('Template name').fill(name);
await page.getByLabel('Template name').pressSequentially(name);

await page.getByLabel('Subject line').fill('E2E subject');
await page.getByLabel('Subject line').pressSequentially('E2E subject');

await page.getByLabel('Message').fill('E2E Message');
await page.getByLabel('Message').pressSequentially('E2E Message');

await page.getByText('Save and preview').click({
position: {
Expand All @@ -103,12 +104,15 @@ export async function createSmsTemplate(
'/templates/create-text-message-template'
);

await page.waitForLoadState('load');
await expect(page.getByTestId('navigation-links')).toBeVisible();
await expect(page.getByTestId('character-message-count')).toBeVisible();

await page.getByLabel('Template name').fill(name);
await page.getByLabel('Template name').pressSequentially(name);

await page.getByLabel('Message').fill('E2E Message');
await page.getByLabel('Message').pressSequentially('E2E Message');

await expect(page.getByTestId('character-message-count')).toBeVisible();
await page.getByText('Save and preview').click({
position: {
x: 50,
Expand All @@ -125,12 +129,15 @@ export async function createNhsAppTemplate(
'/templates/create-nhs-app-template'
);

await page.waitForLoadState('load');
await expect(page.getByTestId('navigation-links')).toBeVisible();
await expect(page.getByTestId('character-count')).toBeVisible();

await page.getByLabel('Template name').fill(name);
await page.getByLabel('Template name').pressSequentially(name);

await page.getByLabel('Message').fill('E2E Message');
await page.getByLabel('Message').pressSequentially('E2E Message');

await expect(page.getByTestId('character-count')).toBeVisible();
await page.getByText('Save and preview').click({
position: {
x: 50,
Expand Down Expand Up @@ -274,7 +281,7 @@ export function copyTemplate(
await basePage.clickButtonByName('Save and preview');
await expect(basePage.pageHeader).toHaveText(editedTemplateName);
await basePage.clickBackLink();
await basePage.page.waitForSelector('text=Message templates', { timeout: 10_000 });
await basePage.page.waitForSelector('text=Message templates');
await basePage.waitForLoad();
await expect(basePage.templateEdited(editedTemplateName)).toBeVisible();

Expand Down
90 changes: 43 additions & 47 deletions tests/security/functions/login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,67 +8,63 @@ import {
getCis2CredentialProvider,
} from "nhs-notify-system-tests-shared";

async function enterCis2TotpCode(
async function enterVerificationCode(
page: Page,
cis2CredentialProvider: Cis2CredentialProvider,
targetHeadingText: string
) {
await page.getByLabel('Enter verification code').fill(cis2CredentialProvider.totp());
await page.getByText(/\W+Submit\W+/).click();

const happyPathSelector = page.getByText(targetHeadingText);
const reVerificationSelector = page.locator(`//button[text()=' Re-enter verification code ']`);
await page.getByText('Submit').click();

await happyPathSelector.or(reVerificationSelector).waitFor({ timeout: 60_000 });
if (await happyPathSelector.isVisible()) {
return true;
await expect(
page.getByText('Message templates')
.or(
page.getByText('Re-enter verification code')
)
.or(
page.getByText('Sign in using an NHS account')
)).toBeVisible({ timeout: 90_000 });

if (await page.getByText('Message templates').isVisible()) {
return;
}
return false;
}

async function enterCis2TotpCodeWithRetry(
page: Page,
cis2CredentialProvider: Cis2CredentialProvider,
targetHeadingText: string
) {
for (var i=0; i<3; i++) {
const success = await enterCis2TotpCode(page, cis2CredentialProvider, targetHeadingText);
if (success) {
return;
}
await page.getByText(/\W+Re-enter verification code\W+/).click();
if (await page.getByText('Re-enter verification code').isVisible()) {
await page.getByText('Re-enter verification code').click();
enterVerificationCode(page, cis2CredentialProvider);

return;
}

if (await page.getByText('Sign in using an NHS account').isVisible()) {
await cis2Login(page);

return;
}

throw new Error('Unexpected outcome');
}

async function loginWithCis2(
export async function cis2Login(
page: Page,
targetHeadingText: string
) {
const cis2CredentialProvider = await getCis2CredentialProvider();

try {
// Notify WebUI - Click the CIS2 login button
const cis2Button = page.getByText("Log in with my Care Identity")
await page.waitForLoadState('networkidle')
await cis2Button.click();

// CIS2 - Select credentials type
await page.getByLabel("Authenticator app").click();
await page.getByText(/\W+Continue\W+/).click();
await page.waitForSelector(`//input[@name='password']`);

// CIS2 - Username/password form
await page.fill('input[name="email"]', cis2CredentialProvider.username);
await page.fill('input[name="password"]', cis2CredentialProvider.password);
await page.getByText(/\W+Continue\W+/).click();
await expect(page.getByText('Enter verification code')).toBeVisible();

// CIS2 - TOTP form
await enterCis2TotpCodeWithRetry(page, cis2CredentialProvider, targetHeadingText);
} catch (error) {
console.error("Error during login:", error);
throw error;
}
await page.waitForLoadState('load');

await page.getByText("Log in with my Care Identity").click();

await page.getByLabel("Authenticator app").click();

await page.getByText('Continue').click();

await page.getByLabel('What is your email address?').fill(cis2CredentialProvider.username);

await page.getByLabel('What is your password?').fill(cis2CredentialProvider.password);

await page.getByText('Continue').click();

await enterVerificationCode(page, cis2CredentialProvider);
}

async function logOut(page: TemplateMgmtBasePage) {
Expand All @@ -77,4 +73,4 @@ async function logOut(page: TemplateMgmtBasePage) {
await expect(page.pageHeader).toHaveText('Sign in');
}

export { loginWithCis2, expect, logOut };
export { expect, logOut };
9 changes: 8 additions & 1 deletion tests/security/tests/routing-config.security.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ const previewAndSelectTemplate = async (
}

test(`User creates a multi-channel routing config`, async ({ page }, { config: { configFile } }) => {
test.setTimeout(180_000);

const templates = await getSeededTemplateConfig(configFile);
await page.goto('/templates/message-plans');
Expand Down Expand Up @@ -111,5 +112,11 @@ test(`User creates a multi-channel routing config`, async ({ page }, { config: {

await expect(page).toHaveURL(new RegExp(`/templates/message-plans/review-and-move-to-production/${routingConfigId}(.*)`));

// remaining pages not ready yet
await page.getByText('Move to production').click();

await expect(page).toHaveURL('/templates/message-plans');

await page.getByText(/Production \(\d+\)/).click();

await expect(page.getByText(routingConfigId)).toBeVisible();
});
10 changes: 5 additions & 5 deletions tests/security/tests/template-mgmt-cis2-login.security.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* eslint-disable security/detect-non-literal-regexp */

import { loginWithCis2, logOut } from '../functions/login';
import { cis2Login, logOut } from '../functions/login';
import { TemplateMgmtBasePage } from '../pages/template-mgmt-base-page';
import {
chooseTemplate,
Expand All @@ -13,7 +13,7 @@ import test from 'playwright/test';
import { TemplateMgmtLetterPage } from '../pages/template-mgmt-letter-page';

test.use({ storageState: { cookies: [], origins: [] } });
test.setTimeout(180_000);
test.setTimeout(300_000);

/**
* Intention is to cover:
Expand All @@ -40,14 +40,14 @@ test('User logs in via CIS2, saves data in templates, logs out and logs back in
const name = 'CIS2 login test';

await startPage({ basePage });
await loginWithCis2(basePage.page, 'Message templates');
await cis2Login(basePage.page);
await startNewTemplate(props);
await chooseTemplate(props, channel);
await createEmailTemplate(page, name);
await previewPage(props, channelPath, name);
await context.storageState({ path: 'login-state/cis2.json' });
await logOut(basePage);
await page.waitForLoadState('networkidle');
await page.waitForLoadState('load');
await startPage({ basePage });
await loginWithCis2(basePage.page, 'Message templates');
await cis2Login(basePage.page);
});
4 changes: 4 additions & 0 deletions tests/test-team/config/dev.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ export default defineConfig({
slowMo: 0,
},
video: 'on',
viewport: {
height: 1200,
width: 1600,
},
headless: true
},
},
Expand Down
102 changes: 45 additions & 57 deletions tests/test-team/functions/login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,75 +5,63 @@ import {
getCis2CredentialProvider,
} from 'nhs-notify-system-tests-shared';

async function enterCis2TotpCode(
async function enterVerificationCode(
page: Page,
cis2CredentialProvider: Cis2CredentialProvider,
targetHeadingText: string
) {
await page.getByLabel('Enter verification code').fill(cis2CredentialProvider.totp());
await page.getByText(/\W+Submit\W+/).click();

const happyPathSelector = page.getByText(targetHeadingText);
const reVerificationSelector = page.locator(
`//button[text()=' Re-enter verification code ']`
);

await happyPathSelector
.or(reVerificationSelector)
.waitFor({ timeout: 30_000 });
if (await happyPathSelector.isVisible()) {
return true;

await page.getByText('Submit').click();

await expect(
page.getByText('Message templates')
.or(
page.getByText('Re-enter verification code')
)
.or(
page.getByText('Sign in using an NHS account')
)).toBeVisible({ timeout: 90_000 });

if (await page.getByText('Message templates').isVisible()) {
return;
}
return false;
}

async function enterCis2TotpCodeWithRetry(
page: Page,
cis2CredentialProvider: Cis2CredentialProvider,
targetHeadingText: string
) {
for (var i = 0; i < 3; i++) {
const success = await enterCis2TotpCode(
page,
cis2CredentialProvider,
targetHeadingText
);
if (success) {
return;
}
await page.getByText(/\W+Re-enter verification code\W+/).click();
if (await page.getByText('Re-enter verification code').isVisible()) {
await page.getByText('Re-enter verification code').click();
enterVerificationCode(page, cis2CredentialProvider);

return;
}

if (await page.getByText('Sign in using an NHS account').isVisible()) {
await cis2Login(page);

return;
}

throw new Error('Unexpected outcome');
}

async function loginWithCis2(
export async function cis2Login(
page: Page,
targetHeadingText: string
) {
const cis2CredentialProvider = await getCis2CredentialProvider();

try {
// Notify WebUI - Click the CIS2 login button
const cis2Button = page.getByText('Log in with my Care Identity');
await page.waitForLoadState('networkidle');
await cis2Button.click();

// CIS2 - Select credentials type
await page.getByLabel('Authenticator app').click();
await page.getByText(/\W+Continue\W+/).click();
await page.waitForSelector(`//input[@name='password']`);

// CIS2 - Username/password form
await page.fill('input[name="email"]', cis2CredentialProvider.username);
await page.fill('input[name="password"]', cis2CredentialProvider.password);
await page.getByText(/\W+Continue\W+/).click();
await expect(page.getByText('Enter verification code')).toBeVisible();

// CIS2 - TOTP form
await enterCis2TotpCodeWithRetry(page, cis2CredentialProvider, targetHeadingText);
} catch (error) {
console.error('Error during login:', error);
throw error;
}
await page.waitForLoadState('load');

await page.getByText("Log in with my Care Identity").click();

await page.getByLabel("Authenticator app").click();

await page.getByText('Continue').click();

await page.getByLabel('What is your email address?').fill(cis2CredentialProvider.username);

await page.getByLabel('What is your password?').fill(cis2CredentialProvider.password);

await page.getByText('Continue').click();

await enterVerificationCode(page, cis2CredentialProvider);
}

async function logOut(page: TemplateMgmtBasePage) {
Expand All @@ -82,4 +70,4 @@ async function logOut(page: TemplateMgmtBasePage) {
await expect(page.pageHeader).toHaveText('Sign in');
}

export { loginWithCis2, expect, logOut };
export { expect, logOut };
Loading
Loading