diff --git a/.github/workflows/run-acceptance-tests.yml b/.github/workflows/run-acceptance-tests.yml index ba5f106..dfe0a29 100644 --- a/.github/workflows/run-acceptance-tests.yml +++ b/.github/workflows/run-acceptance-tests.yml @@ -11,9 +11,13 @@ jobs: env: TEST_USER_SUB: ${{ secrets.TEST_USER_SUB }} TEST_USER_PHONE_NUMBER_VERIFIED: ${{ secrets.TEST_USER_PHONE_NUMBER_VERIFIED }} + TEST_USER_PHONE_NUMBER: ${{ secrets.TEST_USER_PHONE_NUMBER }} TEST_USER_EMAIL_VERIFIED: ${{ secrets.TEST_USER_EMAIL_VERIFIED }} TEST_USER_EMAIL: ${{ secrets.TEST_USER_EMAIL }} TEST_USER_PASSWORD: ${{ secrets.TEST_USER_PASSWORD }} + TEST_USER_PHONE_VERIFY_CODE: ${{ secrets.TEST_USER_PHONE_VERIFY_CODE }} + TEST_USER_PASSPORT: ${{ secrets.TEST_USER_PASSPORT }} + TEST_USER_ADDRESS: ${{ secrets.TEST_USER_ADDRESS }} services: selenium: image: selenium/standalone-chrome:latest diff --git a/tests/acceptance/data/address.js b/tests/acceptance/data/address.js new file mode 100644 index 0000000..e089565 --- /dev/null +++ b/tests/acceptance/data/address.js @@ -0,0 +1,26 @@ +export const ADDRESS = [ + { + uprn: "10022812929", + subBuildingName: "FLAT 5", + buildingName: "WEST LEA", + buildingNumber: "16", + dependentStreetName: "KINGS PARK", + streetName: "HIGH STREET", + doubleDependentAddressLocality: "EREWASH", + dependentAddressLocality: "LONG EATON", + addressLocality: "GREAT MISSENDEN", + postalCode: "HP16 0AL", + addressCountry: "GB", + validFrom: "2022-01-01", + }, + { + uprn: "10002345923", + buildingName: "SAWLEY MARINA", + streetName: "INGWORTH ROAD", + dependentAddressLocality: "LONG EATON", + addressLocality: "NOTTINGHAM", + postalCode: "BH12 1JY", + addressCountry: "GB", + validUntil: "2022-01-01", + }, +] \ No newline at end of file diff --git a/tests/acceptance/data/passport.js b/tests/acceptance/data/passport.js new file mode 100644 index 0000000..d046c57 --- /dev/null +++ b/tests/acceptance/data/passport.js @@ -0,0 +1,7 @@ +export const PASSPORT = [ + { + documentNumber: "1223456", + icaoIssuerCode: "GBR", + expiryDate: "2032-02-02", + }, +] \ No newline at end of file diff --git a/tests/acceptance/features/authentication.feature b/tests/acceptance/features/authentication.feature index 53854a0..2ed2b43 100644 --- a/tests/acceptance/features/authentication.feature +++ b/tests/acceptance/features/authentication.feature @@ -1,14 +1,16 @@ Feature: Authentication - Scenario: User successfully login without 2FA - Given the user comes from the stub relying party with options: "2fa-off" + Scenario: User successfully login + Given the user comes from the stub relying party with default options Then the user is taken to the "Create your GOV.UK One Login or sign in" page When the user selects sign in Then the user is taken to the "Enter your email" page When user enters "TEST_USER_EMAIL" email address Then the user is taken to the "Enter your password" page When the user enters their password + Then the user is taken to the "Check your phone" page + When the user enters the six digit security code from their phone Then the user is returned to the service - And the RP receives the expected user info + And the RP receives the expected auth only user info And the user logs out When the simulator is sent the configuration - Then the simulator returns the expected user info + Then the simulator returns the expected auth only user info diff --git a/tests/acceptance/features/identity.feature b/tests/acceptance/features/identity.feature new file mode 100644 index 0000000..30741e9 --- /dev/null +++ b/tests/acceptance/features/identity.feature @@ -0,0 +1,18 @@ +Feature: Identity + Scenario: User successfully gets identity response + Given the user comes from the stub relying party with options: "loc-P2" + Then the user is taken to the "Create your GOV.UK One Login or sign in" page + When the user selects sign in + Then the user is taken to the "Enter your email" page + When user enters "TEST_USER_EMAIL" email address + Then the user is taken to the "Enter your password" page + When the user enters their password + Then the user is taken to the "Check your phone" page + When the user enters the six digit security code from their phone + Then the user is taken to the "IPV stub" page + When the user clicks the continue button + Then the user is returned to the service via processing identity + And the RP receives the expected identity user info + And the user logs out + When the simulator is sent the identity configuration + Then the simulator returns the expected identity user info diff --git a/tests/acceptance/pages/base-page.js b/tests/acceptance/pages/base-page.js index 9f82c08..6d87d0a 100644 --- a/tests/acceptance/pages/base-page.js +++ b/tests/acceptance/pages/base-page.js @@ -66,8 +66,6 @@ module.exports = class BasePage { elementWithIdContainsText = async (elementId, text) => { await this.waitForReadyStateComplete(); - const element = await this.page.findElement(By.xpath(`//*[@id='${elementId}']`)); - console.log(await element.getText()); await this.page.findElement(By.xpath(`//*[contains(text(), '${text}') and @id='${elementId}']`)); } } \ No newline at end of file diff --git a/tests/acceptance/pages/check-your-phone-page.js b/tests/acceptance/pages/check-your-phone-page.js new file mode 100644 index 0000000..9a0ea07 --- /dev/null +++ b/tests/acceptance/pages/check-your-phone-page.js @@ -0,0 +1,19 @@ +const BasePage = require("./base-page.js"); +const { By } = require("selenium-webdriver"); + +module.exports = class CheckYourPhonePage extends BasePage { + constructor(page) { + super(page); + } + + phoneCodeField = By.id("code"); + + enterCorrectPhoneCodeAndContinue = async () => { + await this.enterPhoneCode(process.env.TEST_USER_PHONE_VERIFY_CODE ?? ""); + await this.findAndClickContinue(); + } + + enterPhoneCode = async (phoneCode) => { + await this.clearFieldAndEnter(this.phoneCodeField, phoneCode); + } +} \ No newline at end of file diff --git a/tests/acceptance/pages/enter-your-password-page.js b/tests/acceptance/pages/enter-your-password-page.js index 526e2e8..886be54 100644 --- a/tests/acceptance/pages/enter-your-password-page.js +++ b/tests/acceptance/pages/enter-your-password-page.js @@ -12,8 +12,8 @@ module.exports = class EnterYourPasswordPage extends BasePage { await this.clearFieldAndEnter(this.passwordField, password); } - enterPasswordAndContinue = async (emailAddress) => { - await this.enterPassword(emailAddress); + enterPasswordAndContinue = async (password) => { + await this.enterPassword(password); await this.findAndClickContinue(); } } \ No newline at end of file diff --git a/tests/acceptance/pages/rp-stub-page.js b/tests/acceptance/pages/rp-stub-page.js index 638141f..887e3e0 100644 --- a/tests/acceptance/pages/rp-stub-page.js +++ b/tests/acceptance/pages/rp-stub-page.js @@ -1,11 +1,17 @@ -const { By } = require("selenium-webdriver"); const BasePage = require("./base-page.js"); +const { By } = require("selenium-webdriver"); module.exports = class RpStubPage extends BasePage { constructor(page) { super(page); } + goToRpStubAndContinue = async () => { + await this.page.get(this.RP_URL.toString()); + await this.waitForThisText("Request Object"); + await this.findAndClickContinue(); + } + goToRpStub = async () => { await this.page.get(this.RP_URL.toString()); await this.waitForThisText("Request Object"); diff --git a/tests/acceptance/step_definitions/common-step-def.js b/tests/acceptance/step_definitions/common-step-def.js index 1d229f1..eabb632 100644 --- a/tests/acceptance/step_definitions/common-step-def.js +++ b/tests/acceptance/step_definitions/common-step-def.js @@ -1,10 +1,13 @@ const { When, Then } = require('@cucumber/cucumber'); const BasePage = require("../pages/base-page.js"); -const { equal } = require("node:assert"); +const { deepStrictEqual } = require("node:assert"); +const { PASSPORT } = require("../data/passport"); +const { ADDRESS } = require("../data/address"); const TEST_USER_INFO_RESPONSE = { sub: process.env.TEST_USER_SUB, phone_number_verified: process.env.TEST_USER_PHONE_NUMBER_VERIFIED === "true", + phone_number: process.env.TEST_USER_PHONE_NUMBER, email_verified: process.env.TEST_USER_EMAIL_VERIFIED === "true", email: process.env.TEST_USER_EMAIL, }; @@ -13,9 +16,27 @@ const TEST_USER_INFO_REQUEST = { sub: process.env.TEST_USER_SUB, email: process.env.TEST_USER_EMAIL, emailVerified: process.env.TEST_USER_EMAIL_VERIFIED === "true", - phoneNumberVerified: process.env.TEST_USER_PHONE_NUMBER_VERIFIED === "true" + phoneNumberVerified: process.env.TEST_USER_PHONE_NUMBER_VERIFIED === "true", + phoneNumber: process.env.TEST_USER_PHONE_NUMBER, }; +const TEST_USER_INFO_IDENTITY_REQUEST = { ...TEST_USER_INFO_REQUEST, + coreIdentityVerifiableCredentials: "STUB_IDENTITY", + passportDetails: PASSPORT, + postalAddressDetails: ADDRESS, +} + +const TEST_USER_INFO_IDENTITY_RESPONSE = { + sub: process.env.TEST_USER_SUB, + emailVerified: process.env.TEST_USER_EMAIL_VERIFIED === "true", + phoneNumberVerified: process.env.TEST_USER_PHONE_NUMBER_VERIFIED === "true", + phoneNumber: process.env.TEST_USER_PHONE_NUMBER, + "https://vocab.account.gov.uk/v1/passport": PASSPORT, + "https://vocab.account.gov.uk/v1/coreIdentityJWT": "STUB_IDENTITY", + "https://vocab.account.gov.uk/v1/address": ADDRESS, + email: process.env.TEST_USER_EMAIL, +} + Then("the user is taken to the {string} page", async function (pageTitle){ const page = new BasePage(this.driver); await page.waitForPageLoad(pageTitle); @@ -31,13 +52,23 @@ Then("the user is returned to the service", async function () { await page.waitForPageLoad("Example - GOV.UK - User Info"); }); +Then("the user is returned to the service via processing identity", { timeout: 60 * 1000 }, async function () { + const page = new BasePage(this.driver); + await page.waitForPageLoad("Example - GOV.UK - User Info"); +}); + Then("the user logs out", async function () { const page = new BasePage(this.driver); await page.findAndClickButtonByText("Log out"); await page.waitForPageLoad("Signed out"); }); -Then("the RP receives the expected user info", async function () { +Then("the RP receives the expected auth only user info", async function () { + const page = new BasePage(this.driver); + await page.elementWithIdContainsText("user-info-response", JSON.stringify(TEST_USER_INFO_RESPONSE)); +}); + +Then("the RP receives the expected identity user info", async function () { const page = new BasePage(this.driver); await page.elementWithIdContainsText("user-info-response", JSON.stringify(TEST_USER_INFO_RESPONSE)); }); @@ -56,7 +87,26 @@ When("the simulator is sent the configuration", async function () { await fetch('http://localhost:3000/config', configRequestOptions); }) -Then("the simulator returns the expected user info", async function () { - const authorizeResponse = await fetch('http://localhost:3000/authorize?vtr=%5B%22Cl%22%5D&scope=openid+email&response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A3001%2Fcallback&state=QL1o9IKHyfTr4BpTCiMeROYKyd-8-k6vytO8OaUZspI&prompt=none&nonce=61SGsT-UYLpgIS2DmBKP-JUkMiqJx1jhe6mk8RpWjRQ&client_id=HGIOgho9HIRhgoepdIOPFdIUWgewi0jw'); - equal(await authorizeResponse.text(), JSON.stringify(TEST_USER_INFO_RESPONSE)); +When("the simulator is sent the identity configuration", async function () { + const configRequestOptions = { + method: 'POST', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + "responseConfiguration": TEST_USER_INFO_IDENTITY_REQUEST + }), + }; + await fetch('http://localhost:3000/config', configRequestOptions); +}) + +Then("the simulator returns the expected auth only user info", async function () { + const authorizeResponse = await fetch('http://localhost:3000/authorize?vtr=%5B%22Cl.Cm%22%5D&scope=openid+email+phone&response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A3001%2Fcallback&state=QL1o9IKHyfTr4BpTCiMeROYKyd-8-k6vytO8OaUZspI&prompt=none&nonce=61SGsT-UYLpgIS2DmBKP-JUkMiqJx1jhe6mk8RpWjRQ&client_id=HGIOgho9HIRhgoepdIOPFdIUWgewi0jw'); + deepStrictEqual(await authorizeResponse.json(), TEST_USER_INFO_RESPONSE); +}); + +Then("the simulator returns the expected identity user info", async function () { + const authorizeResponse = await fetch('http://localhost:3000/authorize?vtr=%5B%22P2.Cl.Cm%22%5D&scope=openid+email+phone&claims=%7B%22userinfo%22%3A%7B%22https%3A%5C%2F%5C%2Fvocab.account.gov.uk%5C%2Fv1%5C%2Fpassport%22%3A%7B%22essential%22%3Atrue%7D%2C%22https%3A%5C%2F%5C%2Fvocab.account.gov.uk%5C%2Fv1%5C%2FcoreIdentityJWT%22%3A%7B%22essential%22%3Atrue%7D%2C%22https%3A%5C%2F%5C%2Fvocab.account.gov.uk%5C%2Fv1%5C%2Faddress%22%3A%7B%22essential%22%3Atrue%7D%7D%7D&response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A3001%2Fcallback&state=QL1o9IKHyfTr4BpTCiMeROYKyd-8-k6vytO8OaUZspI&prompt=none&nonce=61SGsT-UYLpgIS2DmBKP-JUkMiqJx1jhe6mk8RpWjRQ&client_id=HGIOgho9HIRhgoepdIOPFdIUWgewi0jw'); + deepStrictEqual(await authorizeResponse.json(), TEST_USER_INFO_IDENTITY_RESPONSE); }); diff --git a/tests/acceptance/step_definitions/login-step-def.js b/tests/acceptance/step_definitions/login-step-def.js index 9c26bc7..169dd26 100644 --- a/tests/acceptance/step_definitions/login-step-def.js +++ b/tests/acceptance/step_definitions/login-step-def.js @@ -2,6 +2,7 @@ const EnterYourPasswordPage = require("../pages/enter-your-password-page.js"); const EnterYourEmailAddressToSignInPage = require("../pages/enter-your-email-address-to-sign-in-page.js"); const CreateOrSignInPage = require("../pages/create-or-sign-in-page.js"); const { When } = require("@cucumber/cucumber"); +const CheckYourPhonePage = require("../pages/check-your-phone-page"); When("the user selects sign in", async function () { @@ -21,4 +22,9 @@ When("the user enters their password", async function () { await enterYourPasswordPage.enterPasswordAndContinue(process.env.TEST_USER_PASSWORD ?? ""); }); +When("the user enters the six digit security code from their phone", async function () { + const checkYourPhonePage = new CheckYourPhonePage(this.driver); + await checkYourPhonePage.enterCorrectPhoneCodeAndContinue(); +}); + const sleep = async (ms) => await new Promise(resolve => setTimeout(resolve, ms)) \ No newline at end of file diff --git a/tests/acceptance/step_definitions/rp-stub-step-def.js b/tests/acceptance/step_definitions/rp-stub-step-def.js index 5489938..e91d2a8 100644 --- a/tests/acceptance/step_definitions/rp-stub-step-def.js +++ b/tests/acceptance/step_definitions/rp-stub-step-def.js @@ -2,7 +2,12 @@ const RpStubPage = require("../pages/rp-stub-page.js"); const { When } = require("@cucumber/cucumber"); -When("the user comes from the stub relying party with options: {string}", async function (options) { +When("the user comes from the stub relying party with default options", async function () { + const rpStubPage = new RpStubPage(this.driver); + await rpStubPage.goToRpStubAndContinue(); +}); + +When("the user comes from the stub relying party with options: {string}", async function (options){ const rpStubPage = new RpStubPage(this.driver); await rpStubPage.goToRpStub(); await rpStubPage.selectRpOptionsByIdAndContinue(options);