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
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@
"release:connect-web-js": "./release_connect_web_js.sh",
"test:e2e:local": "ts-node-esm ./scripts/e2eTests.ts",
"test:e2e:sdk": "lerna run e2e:sdk",
"test:e2e:ui:commitly": "lerna run e2e:ui:commitly",
"test:e2e:ui:nightly": "lerna run e2e:ui:nightly",
"test:e2e:ui": "lerna run e2e:ui",
"test:e2e:report": "lerna run e2e:report"
},
"devDependencies": {
Expand Down
3 changes: 1 addition & 2 deletions packages/tests-e2e/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@
"url": "git+https://github.com/corbado/javascript.git"
},
"scripts": {
"e2e:ui:commitly": "playwright test --config=playwright.config.ui.ts --project=commitly",
"e2e:ui:nightly": "playwright test --config=playwright.config.ui.ts --project=nightly",
"e2e:ui": "playwright test --config=playwright.config.ui.ts",
"e2e:report": "npx playwright show-report"
},
"bugs": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { Page } from '@playwright/test';
import { expect } from '@playwright/test';

import type { SocialProviderType } from '../../utils/constants';
import { repeatSocialLogin, socialLogin } from './socialLogin';

export class LoginInitBlockModel {
page: Page;
Expand Down Expand Up @@ -38,6 +39,14 @@ export class LoginInitBlockModel {
await this.page.getByRole('button', { name: 'Continue' }).click();
}

async submitSocialMicrosoft(email: string, password: string) {
await socialLogin(this.page, email, password);
}

async resubmitSocialMicrosoft() {
await repeatSocialLogin(this.page);
}

submitPasskeyButton() {
return this.page.locator('.cb-last-identifier').click();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { expect } from '@playwright/test';

import type { SocialProviderType } from '../../utils/constants';
import { getRandomIntegerN } from '../../utils/random';
import { repeatSocialLogin, socialLogin } from './socialLogin';

export class SignupInitBlockModel {
page: Page;
Expand Down Expand Up @@ -53,31 +54,15 @@ export class SignupInitBlockModel {
}

submitPrimary() {
return this.page.getByRole('button', { name: 'Continue' }).click();
return this.page.getByRole('button', { name: 'Continue', exact: true }).click();
}

async submitSocialMicrosoft() {
const microsoftEmail = process.env.PLAYWRIGHT_MICROSOFT_EMAIL ?? '';
const microsoftPassword = process.env.PLAYWRIGHT_MICROSOFT_PASSWORD ?? '';

await this.page.getByTitle(`Continue with Microsoft`).click();
await expect(this.page.getByRole('heading', { level: 1 })).toHaveText('Sign in');

await this.page.getByRole('textbox', { name: 'email' }).click();
await this.page.getByRole('textbox', { name: 'email' }).fill(microsoftEmail);
await expect(this.page.getByRole('textbox', { name: 'email' })).toHaveValue(microsoftEmail);

await this.page.getByRole('button', { name: 'Next' }).click();
await expect(this.page.getByRole('heading', { level: 1 })).toHaveText('Enter password');

await this.page.getByPlaceholder('Password').click();
await this.page.getByPlaceholder('Password').fill(microsoftPassword);
await expect(this.page.getByPlaceholder('Password')).toHaveValue(microsoftPassword);

await this.page.getByRole('button', { name: 'Sign in' }).click();
await expect(this.page.getByRole('heading', { level: 1 })).toHaveText('Stay signed in?');
async submitSocialMicrosoft(email: string, password: string) {
await socialLogin(this.page, email, password);
}

await this.page.getByRole('button', { name: 'No' }).click();
async resubmitSocialMicrosoft() {
await repeatSocialLogin(this.page);
}

expectErrorMissingUsername(): Promise<void> {
Expand Down
30 changes: 30 additions & 0 deletions packages/tests-e2e/src/models/corbado-auth-blocks/socialLogin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import type { Page } from '@playwright/test';
import { expect } from '@playwright/test';

export const socialLogin = async (page: Page, email: string, password: string) => {
await page.getByTitle(`Continue with Microsoft`).click();
await expect(page.getByRole('heading', { level: 1 })).toHaveText('Sign in');

await page.getByRole('textbox', { name: 'email' }).click();
await page.getByRole('textbox', { name: 'email' }).fill(email);
await expect(page.getByRole('textbox', { name: 'email' })).toHaveValue(email);

await page.getByRole('button', { name: 'Next' }).click();
await expect(page.getByRole('heading', { level: 1 })).toHaveText('Enter password');

await page.getByPlaceholder('Password').click();
await page.getByPlaceholder('Password').fill(password);
await expect(page.getByPlaceholder('Password')).toHaveValue(password);

await page.getByRole('button', { name: 'Sign in' }).click();
await expect(page.getByRole('heading', { level: 1 })).toHaveText('Stay signed in?');

await page.getByRole('button', { name: 'No' }).click();
};

export const repeatSocialLogin = async (page: Page) => {
await page.getByTitle(`Continue with Microsoft`).click();
await expect(page.getByRole('heading', { level: 1 })).toHaveText('Let this app access your info? (1 of 1 apps)');

await page.getByRole('button', { name: 'Accept' }).click();
};
108 changes: 94 additions & 14 deletions packages/tests-e2e/src/ui/corbado-auth-general/socials.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
IdentifierType,
IdentifierVerification,
ScreenNames,
socialOperationTimeout,
SocialProviderType,
} from '../../utils/constants';
import {
Expand All @@ -17,13 +18,19 @@ import {
test.describe('social logins', () => {
let projectId: string;

test.beforeAll(async () => {
// Microsoft social login requires longer timeout
test.use({
actionTimeout: socialOperationTimeout,
navigationTimeout: socialOperationTimeout,
});

test.beforeEach(async () => {
projectId = await createProjectNew();

await setComponentConfig(
projectId,
[
makeIdentifier(IdentifierType.Email, IdentifierEnforceVerification.Signup, true, [
makeIdentifier(IdentifierType.Email, IdentifierEnforceVerification.None, true, [
IdentifierVerification.EmailOtp,
]),
],
Expand All @@ -35,7 +42,7 @@ test.describe('social logins', () => {
);
});

test.afterAll(async () => {
test.afterEach(async () => {
await deleteProjectNew(projectId);
});

Expand All @@ -59,29 +66,102 @@ test.describe('social logins', () => {
);
});

// this covers signup + login
test.skip('signup with socials should be possible (account does not exist)', async ({ model }) => {
test('signup with socials should be possible (account does not exist)', async ({ model }) => {
await model.load(projectId, true, 'signup-init');

await model.signupInit.submitSocialMicrosoft();
const email = process.env.PLAYWRIGHT_MICROSOFT_EMAIL ?? '';
const password = process.env.PLAYWRIGHT_MICROSOFT_PASSWORD ?? '';

await model.signupInit.submitSocialMicrosoft(email, password);
await model.expectScreen(ScreenNames.PasskeyAppend1);
});

test.skip('signup with social should be possible (account exists, social has been linked)', async ({ model }) => {
await model.load(projectId, true, 'signup-init');

const email = process.env.PLAYWRIGHT_MICROSOFT_EMAIL_LINKED ?? '';
const password = process.env.PLAYWRIGHT_MICROSOFT_PASSWORD ?? '';

await model.signupInit.submitSocialMicrosoft(email, password);
await model.expectScreen(ScreenNames.PasskeyAppend1);
await model.passkeyAppend.startPasskeyOperation(true);
await model.expectScreen(ScreenNames.End);
await model.logout();
});

test.skip('signup with social should be possible (account exists, social has been linked)', async ({ model }) => {});
await model.load(projectId, true, 'signup-init');

await model.signupInit.resubmitSocialMicrosoft();
// TODO: should successfully log in, but gets redirected to login-init instead.
await model.expectScreen(ScreenNames.End);
});

// in that case only identifier based login should be possible
test.skip('signup with social should not be possible (account exists, social has not been linked)', async ({
model,
}) => {});
test('signup with social should not be possible (account exists, social has not been linked)', async ({ model }) => {
await model.load(projectId, true, 'signup-init');

const email = process.env.PLAYWRIGHT_MICROSOFT_EMAIL_UNLINKED ?? '';
const password = process.env.PLAYWRIGHT_MICROSOFT_PASSWORD ?? '';

await model.signupInit.fillEmail(email);
await model.signupInit.submitPrimary();
await model.passkeyAppend.startPasskeyOperation(true);
await model.expectScreen(ScreenNames.End);
await model.logout();

await model.load(projectId, true, 'signup-init');

await model.signupInit.submitSocialMicrosoft(email, password);
await model.expectScreen(ScreenNames.InitLogin);
});

test('login with social should be possible (account does not exist)', async ({ model }) => {
// redirects to passkey append screen
await model.load(projectId, true, 'login-init');

const email = process.env.PLAYWRIGHT_MICROSOFT_EMAIL ?? '';
const password = process.env.PLAYWRIGHT_MICROSOFT_PASSWORD ?? '';
await model.loginInit.submitSocialMicrosoft(email, password);

await model.expectScreen(ScreenNames.PasskeyAppend1);
});

test('login with social should be possible (account exists, social has been linked)', async ({ model }) => {
await model.load(projectId, true, 'signup-init');

const email = process.env.PLAYWRIGHT_MICROSOFT_EMAIL_LINKED ?? '';
const password = process.env.PLAYWRIGHT_MICROSOFT_PASSWORD ?? '';

await model.signupInit.submitSocialMicrosoft(email, password);
await model.expectScreen(ScreenNames.PasskeyAppend1);
await model.passkeyAppend.startPasskeyOperation(true);
await model.expectScreen(ScreenNames.End);
await model.logout();

test.skip('login with social should be possible (account does not exist)', async ({ model }) => {});
await model.load(projectId, true, 'login-init');

test.skip('login with social should be possible (account exists, social has been linked)', async ({ model }) => {});
await model.signupInit.resubmitSocialMicrosoft();
await model.expectScreen(ScreenNames.End);
});

// in that case only identifier based login should be possible
test.skip('login with social should not be possible (account exists, social has not been linked)', async ({
model,
}) => {});
}) => {
await model.load(projectId, true, 'signup-init');

const email = process.env.PLAYWRIGHT_MICROSOFT_EMAIL_UNLINKED ?? '';
const password = process.env.PLAYWRIGHT_MICROSOFT_PASSWORD ?? '';

await model.signupInit.fillEmail(email);
await model.signupInit.submitPrimary();
await model.passkeyAppend.startPasskeyOperation(true);
await model.expectScreen(ScreenNames.End);
await model.logout();

await model.load(projectId, true, 'login-init');

await model.signupInit.submitSocialMicrosoft(email, password);
// TODO: should redirect to login-init screen, but gets successfully logged in insteaad.
await model.expectScreen(ScreenNames.InitLogin);
});
});
3 changes: 2 additions & 1 deletion packages/tests-e2e/src/utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,9 @@ export enum AuthType {

export const emailLinkUrlToken = 'UaTwjBJwyDLMGVbR7WHh';

export const operationTimeout = process.env.CI ? 3000 : 5000;
export const totalTimeout = process.env.CI ? 20000 : 30000;
export const operationTimeout = process.env.CI ? 3000 : 5000;
export const socialOperationTimeout = 10000;
export const waitAfterLoad = 600; // timeout to reduce flakiness due to repetitive reloads

export enum SocialProviderType {
Expand Down
6 changes: 3 additions & 3 deletions playground/react/.env
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
REACT_APP_CORBADO_PROJECT_ID_ManualTesting=pro-3652881945085154854
REACT_APP_CORBADO_PROJECT_ID_LocalDevelopment=pro-2
# REACT_APP_CORBADO_FRONTEND_API_URL_SUFFIX=frontendapi.corbado.io

# REACT_APP_CORBADO_FRONTEND_API_URL_SUFFIX=frontendapi.cloud.corbado-staging.io
REACT_APP_CORBADO_FRONTEND_API_URL_SUFFIX=frontendapi.corbado-dev.io
REACT_APP_CORBADO_FRONTEND_API_URL_SUFFIX=frontendapi.cloud.corbado-staging.io
# REACT_APP_CORBADO_FRONTEND_API_URL_SUFFIX=frontendapi.corbado-dev.io
# REACT_APP_CORBADO_FRONTEND_API_URL_SUFFIX=frontendapi.corbado.io