diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 2d4e28d070dc..26df4ffc97a3 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -150,12 +150,12 @@ jobs: name: Start CockroachDB - uses: browser-actions/setup-chrome@latest name: Install Chrome - - uses: browser-actions/setup-firefox@latest - name: Install Firefox - - uses: browser-actions/setup-geckodriver@latest - name: Install Geckodriver - with: - geckodriver-version: 0.32.0 + # - uses: browser-actions/setup-firefox@latest + # name: Install Firefox + # - uses: browser-actions/setup-geckodriver@latest + # name: Install Geckodriver + # with: + # geckodriver-version: 0.32.0 - uses: ory/ci/checkout@master with: fetch-depth: 2 diff --git a/test/e2e/cypress/integration/profiles/code/login/success.spec.ts b/test/e2e/cypress/integration/profiles/code/login/success.spec.ts index 958f367612ab..94ce753f0322 100644 --- a/test/e2e/cypress/integration/profiles/code/login/success.spec.ts +++ b/test/e2e/cypress/integration/profiles/code/login/success.spec.ts @@ -138,6 +138,12 @@ context("Login success with code method", () => { cy.get(Selectors[app]["submit"]).click() }) + if (app === "express") { + cy.url().should("match", /\/welcome/) + } else { + cy.get('[data-testid="session-content"]').should("contain", email) + } + if (app === "mobile") { cy.get('[data-testid="session-token"]').then((token) => { cy.getSession({ @@ -206,6 +212,12 @@ context("Login success with code method", () => { cy.get(Selectors[app]["submit"]).click() + if (app === "express") { + cy.url().should("match", /\/welcome/) + } else { + cy.get('[data-testid="session-content"]').should("contain", email) + } + if (app === "express") { cy.get('a[href*="sessions"').click() } @@ -274,6 +286,12 @@ context("Login success with code method", () => { cy.get(Selectors[app]["submit"]).click() }) + if (app === "express") { + cy.url().should("match", /\/welcome/) + } else { + cy.get('[data-testid="session-content"]').should("contain", email) + } + if (app === "mobile") { cy.get('[data-testid="session-token"]').then((token) => { cy.getSession({ diff --git a/test/e2e/cypress/integration/profiles/code/registration/success.spec.ts b/test/e2e/cypress/integration/profiles/code/registration/success.spec.ts index 53fd71ac0f66..c715d80cd86e 100644 --- a/test/e2e/cypress/integration/profiles/code/registration/success.spec.ts +++ b/test/e2e/cypress/integration/profiles/code/registration/success.spec.ts @@ -6,6 +6,53 @@ import { gen, MOBILE_URL } from "../../../../helpers" import { routes as express } from "../../../../helpers/express" import { routes as react } from "../../../../helpers/react" +const Selectors = { + mobile: { + identifier: "[data-testid='field/identifier']", + recoveryEmail: "[data-testid='field/email']", + email: "[data-testid='traits.email']", + email2: "[data-testid='traits.email2']", + tos: "[data-testid='traits.tos']", + username: "[data-testid='traits.username']", + code: "[data-testid='field/code'] input", + recoveryCode: "[data-testid='code']", + submitCode: "[data-testid='field/method/code']", + resendCode: "[data-testid='field/resend/code']", + submitRecovery: "[data-testid='field/method/code']", + codeHiddenMethod: "[data-testid='field/method/code']", + }, + express: { + identifier: "[data-testid='login-flow-code'] input[name='identifier']", + recoveryEmail: "input[name=email]", + email: "[data-testid='registration-flow-code'] input[name='traits.email']", + email2: + "[data-testid='registration-flow-code'] input[name='traits.email2']", + tos: "[data-testid='registration-flow-code'] [name='traits.tos'] + label", + username: + "[data-testid='registration-flow-code'] input[name='traits.username']", + code: "input[name='code']", + recoveryCode: "input[name=code]", + submitRecovery: "button[name=method][value=code]", + submitCode: "button[name='method'][value='code']", + resendCode: "button[name='resend'][value='code']", + codeHiddenMethod: "input[name='method'][value='code'][type='hidden']", + }, + react: { + identifier: "input[name='identifier']", + recoveryEmail: "input[name=email]", + email: "input[name='traits.email']", + email2: "input[name='traits.email2']", + tos: "[name='traits.tos'] + label", + username: "input[name='traits.username']", + code: "input[name='code']", + recoveryCode: "input[name=code]", + submitRecovery: "button[name=method][value=code]", + submitCode: "button[name='method'][value='code']", + resendCode: "button[name='resend'][value='code']", + codeHiddenMethod: "input[name='method'][value='code'][type='hidden']", + }, +} + context("Registration success with code method", () => { ;[ { @@ -31,57 +78,7 @@ context("Registration success with code method", () => { }, ].forEach(({ route, login, recovery, profile, app }) => { describe(`for app ${app}`, () => { - const Selectors = { - mobile: { - identifier: "[data-testid='field/identifier']", - recoveryEmail: "[data-testid='field/email']", - email: "[data-testid='traits.email']", - email2: "[data-testid='traits.email2']", - tos: "[data-testid='traits.tos']", - username: "[data-testid='traits.username']", - code: "[data-testid='field/code']", - recoveryCode: "[data-testid='code']", - submitCode: "[data-testid='field/method/code']", - resendCode: "[data-testid='field/method/resend']", - submitRecovery: "[data-testid='field/method/code']", - codeHiddenMethod: "[data-testid='field/method/code']", - }, - express: { - identifier: - "[data-testid='login-flow-code'] input[name='identifier']", - recoveryEmail: "input[name=email]", - email: - "[data-testid='registration-flow-code'] input[name='traits.email']", - email2: - "[data-testid='registration-flow-code'] input[name='traits.email2']", - tos: "[data-testid='registration-flow-code'] [name='traits.tos'] + label", - username: - "[data-testid='registration-flow-code'] input[name='traits.username']", - code: "input[name='code']", - recoveryCode: "input[name=code]", - submitRecovery: "button[name=method][value=code]", - submitCode: "button[name='method'][value='code']", - resendCode: "button[name='resend'][value='code']", - codeHiddenMethod: "input[name='method'][value='code'][type='hidden']", - }, - react: { - identifier: "input[name='identifier']", - recoveryEmail: "input[name=email]", - email: "input[name='traits.email']", - email2: "input[name='traits.email2']", - tos: "[name='traits.tos'] + label", - username: "input[name='traits.username']", - code: "input[name='code']", - recoveryCode: "input[name=code]", - submitRecovery: "button[name=method][value=code]", - submitCode: "button[name='method'][value='code']", - resendCode: "button[name='resend'][value='code']", - codeHiddenMethod: "input[name='method'][value='code'][type='hidden']", - }, - } - before(() => { - cy.deleteMail() cy.useConfigProfile(profile) if (app !== "mobile") { cy.proxy(app) @@ -94,11 +91,11 @@ context("Registration success with code method", () => { cy.visit(route) }) - it("should be able to resend the registration code", async () => { + it("should be able to resend the registration code", () => { const email = gen.email() cy.get(Selectors[app]["email"]).type(email) - cy.get(`${Selectors[app]["tos"]} + label`).click() + cy.get(Selectors[app]["tos"]).click() cy.submitCodeForm(app) cy.get('[data-testid="ui/message/1040005"]').should( @@ -110,7 +107,6 @@ context("Registration success with code method", () => { cy.wrap(code).as("code1"), ) - cy.get(Selectors[app]["email"]).should("have.value", email) cy.get(Selectors[app]["codeHiddenMethod"]).should("exist") cy.get(Selectors[app]["resendCode"]).click() @@ -180,7 +176,13 @@ context("Registration success with code method", () => { cy.get(Selectors[app]["submitCode"]).click() }) + if (app === "express") { + cy.url().should("match", /\/welcome/) + } else { + cy.get('[data-testid="session-content"]').should("contain", email) + } if (app === "mobile") { + cy.get('[data-testid="session-token"]').should("not.be.empty") cy.get('[data-testid="session-token"]').then((token) => { cy.getSession({ expectAal: "aal1", @@ -190,9 +192,6 @@ context("Registration success with code method", () => { cy.wrap(session).as("session") }) }) - - cy.get('[data-testid="session-content"]').should("contain", email) - cy.get('[data-testid="session-token"]').should("not.be.empty") } else { cy.getSession({ expectAal: "aal1", expectMethods: ["code"] }).then( (session) => { @@ -236,7 +235,14 @@ context("Registration success with code method", () => { cy.get(Selectors[app]["submitCode"]).click() }) + if (app === "express") { + cy.url().should("match", /\/welcome/) + } else { + cy.get('[data-testid="session-content"]').should("contain", email) + } + if (app === "mobile") { + cy.get('[data-testid="session-token"]').should("not.be.empty") cy.get('[data-testid="session-token"]').then((token) => { cy.getSession({ expectAal: "aal1", @@ -246,9 +252,6 @@ context("Registration success with code method", () => { cy.wrap(session).as("session") }) }) - - cy.get('[data-testid="session-content"]').should("contain", email) - cy.get('[data-testid="session-token"]').should("not.be.empty") } else { cy.getSession({ expectAal: "aal1", expectMethods: ["code"] }).then( (session) => { @@ -305,6 +308,9 @@ context("Registration success with code method", () => { { hook: "session", }, + { + hook: "show_verification_ui", + }, ]) // Setup complex schema @@ -335,6 +341,7 @@ context("Registration success with code method", () => { cy.get(Selectors[app]["submitCode"]).click() }, ) + cy.get('[data-testid="ui/message/1080003"]').should("be.visible") if (app === "mobile") { cy.visit(MOBILE_URL + "/Home") @@ -359,8 +366,14 @@ context("Registration success with code method", () => { cy.get(Selectors[app]["code"]).type(code) cy.get(Selectors[app]["submitCode"]).click() }) + if (app === "express") { + cy.url().should("match", /\/welcome/) + } else { + cy.get('[data-testid="session-content"]').should("contain", email) + } if (app === "mobile") { + cy.get('[data-testid="session-token"]').should("not.be.empty") cy.get('[data-testid="session-token"]').then((token) => { cy.getSession({ expectAal: "aal1", @@ -370,9 +383,6 @@ context("Registration success with code method", () => { cy.wrap(session).as("session") }) }) - - cy.get('[data-testid="session-content"]').should("contain", email) - cy.get('[data-testid="session-token"]').should("not.be.empty") } else { cy.getSession({ expectAal: "aal1", expectMethods: ["code"] }).then( (session) => { diff --git a/test/e2e/cypress/integration/profiles/oidc/login/success.spec.ts b/test/e2e/cypress/integration/profiles/oidc/login/success.spec.ts index 866f4344eda6..8e381e7acf5d 100644 --- a/test/e2e/cypress/integration/profiles/oidc/login/success.spec.ts +++ b/test/e2e/cypress/integration/profiles/oidc/login/success.spec.ts @@ -39,7 +39,7 @@ context("Social Sign In Successes", () => { cy.loginOidc({ app, url: login }) }) - it.only("should be able to sign up and link existing account", () => { + it("should be able to sign up and link existing account", () => { const email = gen.email() const password = gen.password() diff --git a/test/e2e/cypress/integration/profiles/two-steps/registration/code.spec.ts b/test/e2e/cypress/integration/profiles/two-steps/registration/code.spec.ts index 2b09fa1e6745..bffafb36ee03 100644 --- a/test/e2e/cypress/integration/profiles/two-steps/registration/code.spec.ts +++ b/test/e2e/cypress/integration/profiles/two-steps/registration/code.spec.ts @@ -6,6 +6,57 @@ import { gen, MOBILE_URL } from "../../../../helpers" import { routes as express } from "../../../../helpers/express" import { routes as react } from "../../../../helpers/react" +const Selectors = { + mobile: { + identifier: "[data-testid='field/identifier']", + recoveryEmail: "[data-testid='field/email']", + email: "[data-testid='traits.email']", + email2: "[data-testid='traits.email2']", + website: "[data-testid='traits.website']", + username: "[data-testid='traits.username']", + code: "[data-testid='field/code'] input", + recoveryCode: "[data-testid='code']", + submitCode: "[data-testid='field/method/code']", + resendCode: "[data-testid='field/resend/code']", + credentialSelection: "[data-testid='field/screen/credential-selection']", + submitRecovery: "[data-testid='field/method/code']", + codeHiddenMethod: "[data-testid='field/method/code']", + }, + express: { + identifier: "[data-testid='login-flow-code'] input[name='identifier']", + recoveryEmail: "input[name=email]", + email: "[data-testid='node/input/traits.email'] input[name='traits.email']", + email2: + "[data-testid='node/input/traits.email2'] input[name='traits.email2']", + website: + "[data-testid='node/input/traits.website'] [name='traits.website']", + username: + "[data-testid='node/input/traits.username'] input[name='traits.username']", + code: "input[name='code']", + recoveryCode: "input[name=code]", + submitRecovery: "button[name=method][value=code]", + submitCode: "button[name='method'][value='code']", + resendCode: "button[name='resend'][value='code']", + codeHiddenMethod: "input[name='method'][value='code'][type='hidden']", + credentialSelection: "[name='screen'][value='credential-selection']", + }, + react: { + identifier: "input[name='identifier']", + recoveryEmail: "input[name=email]", + email: "input[name='traits.email']", + email2: "input[name='traits.email2']", + website: "[name='traits.website']", + username: "input[name='traits.username']", + code: "input[name='code']", + recoveryCode: "input[name=code]", + submitRecovery: "button[name=method][value=code]", + submitCode: "button[name='method'][value='code']", + resendCode: "button[name='resend'][value='code']", + codeHiddenMethod: "input[name='method'][value='code'][type='hidden']", + credentialSelection: "[name='screen'][value='credential-selection']", + }, +} + context("Registration success with code method", () => { ;[ { @@ -31,62 +82,7 @@ context("Registration success with code method", () => { }, ].forEach(({ route, login, recovery, profile, app }) => { describe(`for app ${app}`, () => { - const Selectors = { - mobile: { - identifier: "[data-testid='field/identifier']", - recoveryEmail: "[data-testid='field/email']", - email: "[data-testid='traits.email']", - email2: "[data-testid='traits.email2']", - website: "[data-testid='traits.website']", - username: "[data-testid='traits.username']", - code: "[data-testid='field/code'] input", - recoveryCode: "[data-testid='code']", - submitCode: "[data-testid='field/method/code']", - resendCode: "[data-testid='field/resend/code']", - credentialSelection: - "[data-testid='field/screen/credential-selection']", - submitRecovery: "[data-testid='field/method/code']", - codeHiddenMethod: "[data-testid='field/method/code']", - }, - express: { - identifier: - "[data-testid='login-flow-code'] input[name='identifier']", - recoveryEmail: "input[name=email]", - email: - "[data-testid='node/input/traits.email'] input[name='traits.email']", - email2: - "[data-testid='node/input/traits.email2'] input[name='traits.email2']", - website: - "[data-testid='node/input/traits.website'] [name='traits.website']", - username: - "[data-testid='node/input/traits.username'] input[name='traits.username']", - code: "input[name='code']", - recoveryCode: "input[name=code]", - submitRecovery: "button[name=method][value=code]", - submitCode: "button[name='method'][value='code']", - resendCode: "button[name='resend'][value='code']", - codeHiddenMethod: "input[name='method'][value='code'][type='hidden']", - credentialSelection: "[name='screen'][value='credential-selection']", - }, - react: { - identifier: "input[name='identifier']", - recoveryEmail: "input[name=email]", - email: "input[name='traits.email']", - email2: "input[name='traits.email2']", - website: "[name='traits.website']", - username: "input[name='traits.username']", - code: "input[name='code']", - recoveryCode: "input[name=code]", - submitRecovery: "button[name=method][value=code]", - submitCode: "button[name='method'][value='code']", - resendCode: "button[name='resend'][value='code']", - codeHiddenMethod: "input[name='method'][value='code'][type='hidden']", - credentialSelection: "[name='screen'][value='credential-selection']", - }, - } - before(() => { - cy.deleteMail() cy.useConfigProfile(profile) if (app !== "mobile") { cy.proxy(app) @@ -94,12 +90,12 @@ context("Registration success with code method", () => { }) beforeEach(() => { - cy.deleteMail() + cy.deleteMail({ atLeast: 0 }) cy.clearAllCookies() cy.visit(route) }) - it("should be able to resend the registration code", async () => { + it("should be able to resend the registration code", () => { const email = gen.email() const website = "https://www.example.org/" @@ -141,12 +137,9 @@ context("Registration success with code method", () => { cy.get(Selectors[app]["credentialSelection"]).click() cy.submitCodeForm(app) - // Mobile app sends another email when we go back and forth. - if (app === "mobile") { - cy.getRegistrationCodeFromEmail(email).then((code) => { - cy.wrap(code).as("code2") - }) - } + cy.getRegistrationCodeFromEmail(email).then((code) => { + cy.wrap(code).as("code2") + }) cy.get("@code2").then((code2) => { cy.get(Selectors[app]["code"]).clear() @@ -154,7 +147,14 @@ context("Registration success with code method", () => { cy.submitCodeForm(app) }) + if (app === "express") { + cy.url().should("match", /\/welcome/) + } else { + cy.get('[data-testid="session-content"]').should("contain", email) + } + if (app === "mobile") { + cy.get('[data-testid="session-token"]').should("not.be.empty") cy.get('[data-testid="session-token"]').then((token) => { cy.getSession({ expectAal: "aal1", @@ -164,9 +164,6 @@ context("Registration success with code method", () => { cy.wrap(session).as("session") }) }) - - cy.get('[data-testid="session-content"]').should("contain", email) - cy.get('[data-testid="session-token"]').should("not.be.empty") } else { cy.getSession({ expectAal: "aal1", expectMethods: ["code"] }).then( (session) => { diff --git a/test/e2e/cypress/support/commands.ts b/test/e2e/cypress/support/commands.ts index cfaef5ac9185..0b4584646abc 100644 --- a/test/e2e/cypress/support/commands.ts +++ b/test/e2e/cypress/support/commands.ts @@ -845,7 +845,7 @@ Cypress.Commands.add( if (expectSession) { // for some reason react flakes here although the login succeeded and there should be a session it fails if (app === "react") { - cy.wait(2000) // adding arbitrary wait here. not sure if there is a better way in this case + cy.wait(500) // adding arbitrary wait here. not sure if there is a better way in this case } cy.getSession() } else { @@ -922,8 +922,9 @@ Cypress.Commands.add("logout", () => { const c = cookies.find( ({ name }) => name.indexOf("ory_kratos_session") > -1, ) - expect(c).to.not.be.undefined - cy.clearCookie(c.name) + if (c) { + cy.clearCookie(c.name) + } }) cy.noSession() }) diff --git a/test/e2e/profiles/code/.kratos.yml b/test/e2e/profiles/code/.kratos.yml index 0db7cd92b1ca..3e98857e1628 100644 --- a/test/e2e/profiles/code/.kratos.yml +++ b/test/e2e/profiles/code/.kratos.yml @@ -14,6 +14,7 @@ selfservice: after: code: hooks: + - hook: show_verification_ui - hook: session login: diff --git a/test/e2e/run.sh b/test/e2e/run.sh index c0af9664faa2..62b5330adafc 100755 --- a/test/e2e/run.sh +++ b/test/e2e/run.sh @@ -279,7 +279,7 @@ run() { if [ -z ${CYPRESS_RECORD_KEY+x} ]; then (cd test/e2e; npm run test --) else - (cd test/e2e; npm run test -- --record) + (cd test/e2e; npm run test -- --record --tag "${2}" ) fi fi } @@ -350,19 +350,23 @@ export TEST_DATABASE_MEMORY="memory" case "${1:-default}" in sqlite) echo "Database set up at: $TEST_DATABASE_SQLITE" - db="${TEST_DATABASE_SQLITE}" + dsn="${TEST_DATABASE_SQLITE}" + db="sqlite" ;; mysql) - db="${TEST_DATABASE_MYSQL}" + dsn="${TEST_DATABASE_MYSQL}" + db="mysql" ;; postgres) - db="${TEST_DATABASE_POSTGRESQL}" + dsn="${TEST_DATABASE_POSTGRESQL}" + db="postgres" ;; cockroach) - db="${TEST_DATABASE_COCKROACHDB}" + dsn="${TEST_DATABASE_COCKROACHDB}" + db="cockroach" ;; *) @@ -380,4 +384,4 @@ if [[ "${setup}" == "yes" ]]; then prepare fi -run "${db}" +run "${dsn}" "${db}"