mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-12 12:28:42 +00:00
feat!: affine cloud support (#3813)
Co-authored-by: Hongtao Lye <codert.sn@gmail.com> Co-authored-by: liuyi <forehalo@gmail.com> Co-authored-by: LongYinan <lynweklm@gmail.com> Co-authored-by: X1a0t <405028157@qq.com> Co-authored-by: JimmFly <yangjinfei001@gmail.com> Co-authored-by: Peng Xiao <pengxiao@outlook.com> Co-authored-by: xiaodong zuo <53252747+zuoxiaodong0815@users.noreply.github.com> Co-authored-by: DarkSky <25152247+darkskygit@users.noreply.github.com> Co-authored-by: Qi <474021214@qq.com> Co-authored-by: danielchim <kahungchim@gmail.com>
This commit is contained in:
62
tests/affine-cloud/e2e/basic.spec.ts
Normal file
62
tests/affine-cloud/e2e/basic.spec.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import { test } from '@affine-test/kit/playwright';
|
||||
import {
|
||||
createRandomUser,
|
||||
deleteUser,
|
||||
getLoginCookie,
|
||||
} from '@affine-test/kit/utils/cloud';
|
||||
import { openHomePage } from '@affine-test/kit/utils/load-page';
|
||||
import { waitEditorLoad } from '@affine-test/kit/utils/page-logic';
|
||||
import { clickSideBarCurrentWorkspaceBanner } from '@affine-test/kit/utils/sidebar';
|
||||
import { expect } from '@playwright/test';
|
||||
|
||||
let user: {
|
||||
name: string;
|
||||
email: string;
|
||||
password: string;
|
||||
};
|
||||
|
||||
test.beforeEach(async () => {
|
||||
user = await createRandomUser();
|
||||
});
|
||||
|
||||
test.afterEach(async () => {
|
||||
// if you want to keep the user in the database for debugging,
|
||||
// comment this line
|
||||
await deleteUser(user.email);
|
||||
});
|
||||
|
||||
test('server exist', async ({ page }) => {
|
||||
await openHomePage(page);
|
||||
await waitEditorLoad(page);
|
||||
|
||||
const json = await (await fetch('http://localhost:3010')).json();
|
||||
expect(json.message).toMatch(/^AFFiNE GraphQL server/);
|
||||
});
|
||||
|
||||
test('enable cloud success', async ({ page, context }) => {
|
||||
await page.goto('http://localhost:8080');
|
||||
await page.waitForSelector('v-line');
|
||||
|
||||
await clickSideBarCurrentWorkspaceBanner(page);
|
||||
await page.getByTestId('cloud-signin-button').click({
|
||||
delay: 200,
|
||||
});
|
||||
await page.getByPlaceholder('Enter your email address').type(user.email, {
|
||||
delay: 50,
|
||||
});
|
||||
await page.getByTestId('continue-login-button').click({
|
||||
delay: 200,
|
||||
});
|
||||
await page.getByTestId('sign-in-with-password').click({
|
||||
delay: 200,
|
||||
});
|
||||
await page.getByTestId('password-input').type('123456', {
|
||||
delay: 50,
|
||||
});
|
||||
expect(await getLoginCookie(context)).toBeUndefined();
|
||||
await page.getByTestId('sign-in-button').click();
|
||||
await page.waitForTimeout(1000);
|
||||
await page.reload();
|
||||
await waitEditorLoad(page);
|
||||
expect(await getLoginCookie(context)).toBeTruthy();
|
||||
});
|
||||
17
tests/affine-cloud/e2e/login.spec.ts
Normal file
17
tests/affine-cloud/e2e/login.spec.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { test } from '@affine-test/kit/playwright';
|
||||
import { openHomePage } from '@affine-test/kit/utils/load-page';
|
||||
import { waitEditorLoad } from '@affine-test/kit/utils/page-logic';
|
||||
import { clickSideBarCurrentWorkspaceBanner } from '@affine-test/kit/utils/sidebar';
|
||||
import { expect } from '@playwright/test';
|
||||
|
||||
test.describe('login', () => {
|
||||
test('can open login modal in workspace list', async ({ page }) => {
|
||||
await openHomePage(page);
|
||||
await waitEditorLoad(page);
|
||||
await clickSideBarCurrentWorkspaceBanner(page);
|
||||
await page.getByTestId('cloud-signin-button').click({
|
||||
delay: 200,
|
||||
});
|
||||
await expect(page.getByTestId('auth-modal')).toBeVisible();
|
||||
});
|
||||
});
|
||||
12
tests/affine-cloud/package.json
Normal file
12
tests/affine-cloud/package.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "@affine-test/affine-cloud",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"e2e": "yarn playwright test"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@affine-test/fixtures": "workspace:*",
|
||||
"@affine-test/kit": "workspace:*",
|
||||
"@playwright/test": "^1.37.0"
|
||||
}
|
||||
}
|
||||
64
tests/affine-cloud/playwright.config.ts
Normal file
64
tests/affine-cloud/playwright.config.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import type {
|
||||
PlaywrightTestConfig,
|
||||
PlaywrightWorkerOptions,
|
||||
} from '@playwright/test';
|
||||
|
||||
const config: PlaywrightTestConfig = {
|
||||
testDir: './e2e',
|
||||
fullyParallel: !process.env.CI,
|
||||
timeout: process.env.CI ? 50_000 : 30_000,
|
||||
use: {
|
||||
baseURL: 'http://localhost:8081/',
|
||||
browserName:
|
||||
(process.env.BROWSER as PlaywrightWorkerOptions['browserName']) ??
|
||||
'chromium',
|
||||
permissions: ['clipboard-read', 'clipboard-write'],
|
||||
viewport: { width: 1440, height: 800 },
|
||||
actionTimeout: 5 * 1000,
|
||||
locale: 'en-US',
|
||||
trace: 'on-first-retry',
|
||||
video: 'on-first-retry',
|
||||
},
|
||||
forbidOnly: !!process.env.CI,
|
||||
workers: process.env.CI ? 1 : 4,
|
||||
retries: 1,
|
||||
reporter: process.env.CI ? 'github' : 'list',
|
||||
webServer: [
|
||||
// Intentionally not building the web, reminds you to run it by yourself.
|
||||
{
|
||||
command: 'yarn -T run start:web-static',
|
||||
port: 8080,
|
||||
timeout: 120 * 1000,
|
||||
reuseExistingServer: !process.env.CI,
|
||||
env: {
|
||||
COVERAGE: process.env.COVERAGE || 'false',
|
||||
},
|
||||
},
|
||||
{
|
||||
command: 'yarn workspace @affine/server start',
|
||||
port: 3010,
|
||||
timeout: 120 * 1000,
|
||||
reuseExistingServer: !process.env.CI,
|
||||
stdout: 'pipe',
|
||||
stderr: 'pipe',
|
||||
env: {
|
||||
DATABASE_URL:
|
||||
process.env.DATABASE_URL ??
|
||||
'postgresql://affine@localhost:5432/affine',
|
||||
NODE_ENV: 'development',
|
||||
AFFINE_ENV: process.env.AFFINE_ENV ?? 'dev',
|
||||
DEBUG: 'affine:*',
|
||||
FORCE_COLOR: 'true',
|
||||
DEBUG_COLORS: 'true',
|
||||
NEXTAUTH_URL: 'http://localhost:8080',
|
||||
OAUTH_EMAIL_SENDER: 'noreply@toeverything.info',
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
if (process.env.CI) {
|
||||
config.retries = 3;
|
||||
}
|
||||
|
||||
export default config;
|
||||
16
tests/affine-cloud/tsconfig.json
Normal file
16
tests/affine-cloud/tsconfig.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"esModuleInterop": true,
|
||||
"outDir": "lib"
|
||||
},
|
||||
"include": ["e2e"],
|
||||
"references": [
|
||||
{
|
||||
"path": "../kit"
|
||||
},
|
||||
{
|
||||
"path": "../fixtures"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import { resolve } from 'node:path';
|
||||
|
||||
import { expect, test } from '@playwright/test';
|
||||
import { test } from '@affine-test/kit/playwright';
|
||||
import { expect } from '@playwright/test';
|
||||
import express from 'express';
|
||||
import { createProxyMiddleware } from 'http-proxy-middleware';
|
||||
|
||||
|
||||
@@ -4,5 +4,10 @@
|
||||
"esModuleInterop": true,
|
||||
"outDir": "lib"
|
||||
},
|
||||
"include": ["e2e"]
|
||||
"include": ["e2e"],
|
||||
"references": [
|
||||
{
|
||||
"path": "../../kit"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ test('Create new workspace, then delete it', async ({ page, workspace }) => {
|
||||
.getByTestId('delete-workspace-input')
|
||||
.type(currentWorkspaceName as string);
|
||||
const promise = page
|
||||
.getByTestId('affine-toast')
|
||||
.getByTestId('affine-notification')
|
||||
.waitFor({ state: 'attached' });
|
||||
await page.getByTestId('delete-workspace-confirm-button').click();
|
||||
await promise;
|
||||
@@ -46,7 +46,7 @@ test('Create new workspace, then delete it', async ({ page, workspace }) => {
|
||||
|
||||
expect(currentWorkspace.flavour).toContain('local');
|
||||
});
|
||||
|
||||
//FIXME: this test is broken
|
||||
test('Delete last workspace', async ({ page }) => {
|
||||
await openHomePage(page);
|
||||
await waitEditorLoad(page);
|
||||
@@ -60,12 +60,8 @@ test('Delete last workspace', async ({ page }) => {
|
||||
await page
|
||||
.getByTestId('delete-workspace-input')
|
||||
.type(currentWorkspaceName as string);
|
||||
const promise = page
|
||||
.getByTestId('affine-toast')
|
||||
.waitFor({ state: 'attached' });
|
||||
await page.getByTestId('delete-workspace-confirm-button').click();
|
||||
await promise;
|
||||
await page.reload();
|
||||
await openHomePage(page);
|
||||
await expect(page.getByTestId('new-workspace')).toBeVisible();
|
||||
await page.getByTestId('new-workspace').click();
|
||||
await page.type('[data-testid="create-workspace-input"]', 'Test Workspace');
|
||||
|
||||
@@ -124,8 +124,9 @@ test('create multi workspace in the workspace list', async ({
|
||||
await page.waitForTimeout(1000);
|
||||
// check workspace list length
|
||||
{
|
||||
const workspaceCards1 = await page.$$('data-testid=workspace-card');
|
||||
expect(workspaceCards1.length).toBe(3);
|
||||
await page.waitForTimeout(1000);
|
||||
const workspaceCards = page.getByTestId('workspace-card');
|
||||
expect(await workspaceCards.count()).toBe(3);
|
||||
}
|
||||
|
||||
const workspaceChangePromise = page.evaluate(() => {
|
||||
|
||||
@@ -8,8 +8,10 @@ import {
|
||||
} from '@affine-test/kit/utils/page-logic';
|
||||
import { expect, type Page } from '@playwright/test';
|
||||
|
||||
const openQuickSearchByShortcut = async (page: Page) =>
|
||||
const openQuickSearchByShortcut = async (page: Page) => {
|
||||
await withCtrlOrMeta(page, () => page.keyboard.press('k', { delay: 50 }));
|
||||
await page.waitForTimeout(500);
|
||||
};
|
||||
|
||||
async function assertTitle(page: Page, text: string) {
|
||||
const edgeless = page.locator('affine-edgeless-page');
|
||||
|
||||
@@ -18,6 +18,6 @@ test('goto not found workspace', async ({ page }) => {
|
||||
// if doesn't wait for timeout, data won't be saved into indexedDB
|
||||
await page.waitForTimeout(1000);
|
||||
await page.goto(new URL('/workspace/invalid/all', coreUrl).toString());
|
||||
await page.waitForTimeout(1000);
|
||||
await page.waitForTimeout(3000);
|
||||
expect(page.url()).toBe(new URL('/404', coreUrl).toString());
|
||||
});
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
"./utils/*": "./utils/*.ts"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@node-rs/argon2": "^1.5.2",
|
||||
"@playwright/test": "^1.37.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
||||
54
tests/kit/utils/cloud.ts
Normal file
54
tests/kit/utils/cloud.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import { faker } from '@faker-js/faker';
|
||||
import { hash } from '@node-rs/argon2';
|
||||
import type { BrowserContext, Cookie } from '@playwright/test';
|
||||
|
||||
export async function getLoginCookie(
|
||||
context: BrowserContext
|
||||
): Promise<Cookie | undefined> {
|
||||
return (await context.cookies()).find(
|
||||
c => c.name === 'next-auth.session-token'
|
||||
);
|
||||
}
|
||||
|
||||
export async function createRandomUser() {
|
||||
const user = {
|
||||
name: faker.internet.userName(),
|
||||
email: faker.internet.email().toLowerCase(),
|
||||
password: '123456',
|
||||
};
|
||||
const {
|
||||
PrismaClient,
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
} = require('../../../apps/server/node_modules/@prisma/client');
|
||||
const client = new PrismaClient();
|
||||
await client.$connect();
|
||||
await client.user.create({
|
||||
data: {
|
||||
...user,
|
||||
emailVerified: new Date(),
|
||||
password: await hash(user.password),
|
||||
},
|
||||
});
|
||||
await client.$disconnect();
|
||||
|
||||
return client.user.findUnique({
|
||||
where: {
|
||||
email: user.email,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export async function deleteUser(email: string) {
|
||||
const {
|
||||
PrismaClient,
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
} = require('../../../apps/server/node_modules/@prisma/client');
|
||||
const client = new PrismaClient();
|
||||
await client.$connect();
|
||||
await client.user.delete({
|
||||
where: {
|
||||
email,
|
||||
},
|
||||
});
|
||||
await client.$disconnect();
|
||||
}
|
||||
Reference in New Issue
Block a user