Merge branch 'master' into fix/quick-search-input

This commit is contained in:
JimmFly
2023-02-07 10:41:53 +08:00
21 changed files with 149 additions and 130 deletions
+34 -18
View File
@@ -72,13 +72,11 @@ jobs:
needs: build needs: build
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- uses: pnpm/action-setup@v2 - uses: pnpm/action-setup@v2
with: with:
version: 'latest' version: 'latest'
- uses: actions/setup-node@v3
- name: Use Node.js
uses: actions/setup-node@v2
with: with:
node-version: 18.x node-version: 18.x
cache: 'pnpm' cache: 'pnpm'
@@ -96,8 +94,6 @@ jobs:
- name: Install dependencies - name: Install dependencies
run: pnpm install run: pnpm install
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_GITHUB_AUTH_TOKEN }}
- name: Download artifact - name: Download artifact
uses: actions/download-artifact@v3 uses: actions/download-artifact@v3
@@ -105,20 +101,40 @@ jobs:
name: artifact name: artifact
path: packages/app/.next/ path: packages/app/.next/
- name: Lint & E2E Test - name: Lint & E2E Test & Unit Test
run: | run: |
pnpm lint --max-warnings=0 pnpm lint --max-warnings=0
PLAYWRIGHT_BROWSERS_PATH=0 npx playwright install chromium npx playwright install chromium
PLAYWRIGHT_BROWSERS_PATH=0 pnpm test pnpm run test:coverage
PLAYWRIGHT_BROWSERS_PATH=0 pnpm test:dc pnpm run test:unit
env: # env:
NEXT_PUBLIC_FIREBASE_API_KEY: ${{ secrets.NEXT_PUBLIC_FIREBASE_API_KEY }} # NEXT_PUBLIC_FIREBASE_API_KEY: ${{ secrets.NEXT_PUBLIC_FIREBASE_API_KEY }}
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN: ${{ secrets.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN }} # NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN: ${{ secrets.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN }}
NEXT_PUBLIC_FIREBASE_PROJECT_ID: ${{ secrets.NEXT_PUBLIC_FIREBASE_PROJECT_ID }} # NEXT_PUBLIC_FIREBASE_PROJECT_ID: ${{ secrets.NEXT_PUBLIC_FIREBASE_PROJECT_ID }}
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET: ${{ secrets.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET }} # NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET: ${{ secrets.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET }}
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID: ${{ secrets.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID }} # NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID: ${{ secrets.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID }}
NEXT_PUBLIC_FIREBASE_APP_ID: ${{ secrets.NEXT_PUBLIC_FIREBASE_APP_ID }} # NEXT_PUBLIC_FIREBASE_APP_ID: ${{ secrets.NEXT_PUBLIC_FIREBASE_APP_ID }}
NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID: ${{ secrets.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID }} # NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID: ${{ secrets.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID }}
- name: Collect code coverage report
run: pnpm exec nyc report -t .nyc_output --report-dir .coverage --reporter=lcov
- name: Upload e2e test coverage results
uses: codecov/codecov-action@v3
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./.coverage/lcov.info
flags: e2etest
name: affine
fail_ci_if_error: true
- name: Upload test results
if: ${{ failure() }}
uses: actions/upload-artifact@v2
with:
name: test-results-main
path: ./test-results
if-no-files-found: ignore
build-community: build-community:
name: Build Community name: Build Community
-88
View File
@@ -1,88 +0,0 @@
name: Unit Tests
on:
push:
branches: [master]
pull_request:
branches: [master]
jobs:
e2e-test:
timeout-minutes: 60
runs-on: self-hosted
steps:
- uses: actions/checkout@v3
- uses: pnpm/action-setup@v2
with:
version: 'latest'
- uses: actions/setup-node@v3
with:
node-version: 16
registry-url: https://npm.pkg.github.com
scope: '@toeverything'
cache: 'pnpm'
- run: node scripts/module-resolve/ci.cjs
- name: Install dependencies
run: pnpm install --no-frozen-lockfile
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_GITHUB_AUTH_TOKEN }}
- name: Install Playwright browsers
run: npx playwright install chromium
- name: Run E2E tests
run: pnpm run test:coverage
# env:
# NEXT_PUBLIC_FIREBASE_API_KEY: ${{ secrets.NEXT_PUBLIC_FIREBASE_API_KEY }}
# NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN: ${{ secrets.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN }}
# NEXT_PUBLIC_FIREBASE_PROJECT_ID: ${{ secrets.NEXT_PUBLIC_FIREBASE_PROJECT_ID }}
# NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET: ${{ secrets.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET }}
# NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID: ${{ secrets.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID }}
# NEXT_PUBLIC_FIREBASE_APP_ID: ${{ secrets.NEXT_PUBLIC_FIREBASE_APP_ID }}
# NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID: ${{ secrets.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID }}
- name: Collect code coverage report
run: pnpm exec nyc report -t .nyc_output --report-dir .coverage --reporter=lcov
- name: Upload e2e test coverage results
uses: codecov/codecov-action@v3
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./.coverage/lcov.info
flags: e2etest
name: affine
fail_ci_if_error: true
unit-test:
timeout-minutes: 60
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: pnpm/action-setup@v2
with:
version: 'latest'
- uses: actions/setup-node@v3
with:
node-version: 16
registry-url: https://npm.pkg.github.com
scope: '@toeverything'
cache: 'pnpm'
- run: node scripts/module-resolve/ci.cjs
- name: Install dependencies
run: pnpm install --no-frozen-lockfile
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_GITHUB_AUTH_TOKEN }}
- name: Install Playwright browsers
run: npx playwright install chromium
- name: Run Unit tests
run: pnpm run test:unit
+1 -1
View File
@@ -7,7 +7,7 @@ export const NotfoundPage = () => {
const router = useRouter(); const router = useRouter();
return ( return (
<PageContainer> <PageContainer>
<NotFoundTitle> <NotFoundTitle data-testid="notFound">
{t('404 - Page Not Found')} {t('404 - Page Not Found')}
<p> <p>
<Button <Button
@@ -1,5 +1,6 @@
import { PropsWithChildren, ReactNode } from 'react'; import { PropsWithChildren, ReactNode } from 'react';
import Header from './Header'; import Header from './Header';
import QuickSearchButton from './QuickSearchButton';
import { StyledPageListTittleWrapper } from './styles'; import { StyledPageListTittleWrapper } from './styles';
// import QuickSearchButton from './QuickSearchButton'; // import QuickSearchButton from './QuickSearchButton';
@@ -12,7 +13,7 @@ export const PageListHeader = ({ icon, children }: PageListHeaderProps) => {
<StyledPageListTittleWrapper> <StyledPageListTittleWrapper>
{icon} {icon}
{children} {children}
{/* <QuickSearchButton style={{ marginLeft: '5px' }} /> */} <QuickSearchButton />
</StyledPageListTittleWrapper> </StyledPageListTittleWrapper>
</Header> </Header>
); );
@@ -14,7 +14,6 @@ export const PageListEmpty = (props: { listType?: string }) => {
{listType === 'all' && <p>{t('emptyAllPages')}</p>} {listType === 'all' && <p>{t('emptyAllPages')}</p>}
{listType === 'favorite' && <p>{t('emptyFavourite')}</p>} {listType === 'favorite' && <p>{t('emptyFavourite')}</p>}
{listType === 'trash' && <p>{t('emptyTrash')}</p>} {listType === 'trash' && <p>{t('emptyTrash')}</p>}
<p>{t('still designed')}</p>
</div> </div>
); );
}; };
@@ -1,5 +1,10 @@
import { FC, SVGProps } from 'react'; import { FC, SVGProps } from 'react';
import { AllPagesIcon, FavouritesIcon, TrashIcon } from '@blocksuite/icons'; import {
AllPagesIcon,
FavouritesIcon,
TrashIcon,
SettingsIcon,
} from '@blocksuite/icons';
import { useTranslation } from '@affine/i18n'; import { useTranslation } from '@affine/i18n';
export const useSwitchToConfig = ( export const useSwitchToConfig = (
@@ -23,6 +28,13 @@ export const useSwitchToConfig = (
: '', : '',
icon: FavouritesIcon, icon: FavouritesIcon,
}, },
{
title: t('Settings'),
href: currentWorkspaceId
? `/workspace/${currentWorkspaceId}/setting`
: '',
icon: SettingsIcon,
},
{ {
title: t('Trash'), title: t('Trash'),
href: currentWorkspaceId ? `/workspace/${currentWorkspaceId}/trash` : '', href: currentWorkspaceId ? `/workspace/${currentWorkspaceId}/trash` : '',
@@ -23,6 +23,7 @@ export const WorkspaceCard = ({
const { t } = useTranslation(); const { t } = useTranslation();
return ( return (
<StyledCard <StyledCard
data-testid="workspace-card"
onClick={() => { onClick={() => {
onClick(workspaceData); onClick(workspaceData);
}} }}
@@ -32,13 +32,13 @@ export const WorkspaceSelector = () => {
> >
<WorkspaceUnitAvatar <WorkspaceUnitAvatar
size={28} size={28}
name={currentWorkspace?.name ?? 'AFFiNE'} name={currentWorkspace?.name ?? 'AFFiNE Test'}
workspaceUnit={currentWorkspace} workspaceUnit={currentWorkspace}
/> />
</div> </div>
</Avatar> </Avatar>
<WorkspaceName data-testid="workspace-name"> <WorkspaceName data-testid="workspace-name">
{currentWorkspace?.name ?? 'AFFiNE'} {currentWorkspace?.name ?? 'AFFiNE Test'}
</WorkspaceName> </WorkspaceName>
</SelectorWrapper> </SelectorWrapper>
<WorkspaceModal <WorkspaceModal
+6 -1
View File
@@ -67,8 +67,8 @@ const App = ({ Component, pageProps }: AppPropsWithLayout) => {
}; };
const AppDefender = ({ children }: PropsWithChildren) => { const AppDefender = ({ children }: PropsWithChildren) => {
const { synced } = useAppState();
const router = useRouter(); const router = useRouter();
const { synced } = useAppState();
useEffect(() => { useEffect(() => {
if (router.asPath === '/') { if (router.asPath === '/') {
@@ -76,6 +76,11 @@ const AppDefender = ({ children }: PropsWithChildren) => {
} }
}, [router]); }, [router]);
// if you visit /404, you will see the children directly
if (router.route === '/404') {
return <div>{children}</div>;
}
return <div>{synced ? children : <PageLoading />}</div>; return <div>{synced ? children : <PageLoading />}</div>;
}; };
@@ -1,6 +1,6 @@
import { DataCenter } from '@affine/datacenter'; import { DataCenter } from '@affine/datacenter';
const DEFAULT_WORKSPACE_NAME = 'affine'; const DEFAULT_WORKSPACE_NAME = 'AFFiNE Test';
export const createDefaultWorkspace = async (dataCenter: DataCenter) => { export const createDefaultWorkspace = async (dataCenter: DataCenter) => {
return dataCenter.createWorkspace({ return dataCenter.createWorkspace({
-1
View File
@@ -6,7 +6,6 @@
"main": "dist/src/index.js", "main": "dist/src/index.js",
"types": "dist/src/index.d.ts", "types": "dist/src/index.d.ts",
"exports": { "exports": {
"./src/*": "./dist/src/*.js",
".": "./dist/src/index.js" ".": "./dist/src/index.js"
}, },
"scripts": { "scripts": {
-1
View File
@@ -6,7 +6,6 @@
"type": "module", "type": "module",
"types": "dist/src/index.d.ts", "types": "dist/src/index.d.ts",
"exports": { "exports": {
"./src/*": "./dist/src/*.js",
".": "./dist/src/index.js" ".": "./dist/src/index.js"
}, },
"scripts": { "scripts": {
-1
View File
@@ -5,7 +5,6 @@
"main": "dist/src/index.js", "main": "dist/src/index.js",
"types": "dist/src/index.d.ts", "types": "dist/src/index.d.ts",
"exports": { "exports": {
"./src/*": "./dist/src/*.js",
".": "./dist/src/index.js" ".": "./dist/src/index.js"
}, },
"scripts": { "scripts": {
+7 -1
View File
@@ -17,6 +17,7 @@ const config: PlaywrightTestConfig = {
browserName: 'chromium', browserName: 'chromium',
viewport: { width: 1440, height: 800 }, viewport: { width: 1440, height: 800 },
actionTimeout: 5 * 1000, actionTimeout: 5 * 1000,
locale: 'en-US',
// Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer // Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer
// You can open traces locally(`npx playwright show-trace trace.zip`) // You can open traces locally(`npx playwright show-trace trace.zip`)
// or in your browser on [Playwright Trace Viewer](https://trace.playwright.dev/). // or in your browser on [Playwright Trace Viewer](https://trace.playwright.dev/).
@@ -27,7 +28,7 @@ const config: PlaywrightTestConfig = {
fullyParallel: true, fullyParallel: true,
forbidOnly: !!process.env.CI, forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0, retries: process.env.CI ? 3 : 0,
workers: process.env.CI ? '100%' : undefined, workers: process.env.CI ? '100%' : undefined,
webServer: { webServer: {
@@ -39,6 +40,11 @@ const config: PlaywrightTestConfig = {
COVERAGE: process.env.COVERAGE || 'false', COVERAGE: process.env.COVERAGE || 'false',
}, },
}, },
// 'github' for GitHub Actions CI to generate annotations, plus a concise 'dot'
// default 'list' when running locally
// See https://playwright.dev/docs/test-reporters#github-actions-annotations
reporter: process.env.CI ? 'github' : 'list',
}; };
export default config; export default config;
+5
View File
@@ -23,6 +23,11 @@ const config: PlaywrightTestConfig = {
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: 'on-first-retry', trace: 'on-first-retry',
}, },
// 'github' for GitHub Actions CI to generate annotations, plus a concise 'dot'
// default 'list' when running locally
// See https://playwright.dev/docs/test-reporters#github-actions-annotations
reporter: process.env.CI ? 'github' : 'list',
}; };
export default config; export default config;
+2 -3
View File
@@ -8,8 +8,7 @@ loadPage();
test.describe('exception page', () => { test.describe('exception page', () => {
test('visit 404 page', async ({ page }) => { test('visit 404 page', async ({ page }) => {
await page.goto('http://localhost:8080/404'); await page.goto('http://localhost:8080/404');
await page.waitForTimeout(1000); const notFoundTip = page.locator('[data-testid=notFound]');
const notFoundTip = page.getByText('404 - Page Not Found'); await expect(notFoundTip).toBeVisible();
expect(await notFoundTip.isVisible()).toBe(true);
}); });
}); });
+24
View File
@@ -0,0 +1,24 @@
import type { Page } from '@playwright/test';
interface CreateWorkspaceParams {
name: string;
}
export async function createWorkspace(
params: CreateWorkspaceParams,
page: Page
) {
// open workspace list modal
const workspaceName = page.getByTestId('workspace-name');
await workspaceName.click();
// open create workspace modal
await page.locator('.add-icon').click();
// input workspace name
await page.getByPlaceholder('Set a Workspace name').click();
await page.getByPlaceholder('Set a Workspace name').fill(params.name);
// click create button
await page.getByRole('button', { name: 'Create' }).click();
return page.waitForTimeout(300);
}
+40
View File
@@ -0,0 +1,40 @@
import { expect } from '@playwright/test';
import { test } from './libs/playwright.js';
import { loadPage } from './libs/load-page.js';
import { createWorkspace } from './libs/workspace-logic.js';
loadPage();
test.describe('Local first workspace list', () => {
test('just one item in the workspace list at first', async ({ page }) => {
const workspaceName = page.getByTestId('workspace-name');
await workspaceName.click();
expect(
page
.locator('div')
.filter({ hasText: 'AFFiNE TestLocal WorkspaceAvailable Offline' })
.nth(3)
).not.toBeNull();
});
test.skip('create one workspace in the workspace list', async ({ page }) => {
const newWorkspaceNameStr = 'New Workspace';
await createWorkspace({ name: newWorkspaceNameStr }, page);
// check new workspace name
const newWorkspaceName = page.getByTestId('workspace-name');
expect(await newWorkspaceName.textContent()).toBe(newWorkspaceNameStr);
});
test('create multi workspace in the workspace list', async ({ page }) => {
await createWorkspace({ name: 'New Workspace 2' }, page);
await createWorkspace({ name: 'New Workspace 3' }, page);
// show workspace list
const workspaceName = page.getByTestId('workspace-name');
await workspaceName.click();
//check workspace list length
const workspaceCards = await page.$$('data-testid=workspace-card');
expect(workspaceCards.length).toBe(3);
});
});
+6 -6
View File
@@ -5,15 +5,15 @@ import { loadPage } from './libs/load-page.js';
loadPage(); loadPage();
test.describe('Local first default workspace', () => { test.describe('Local first default workspace', () => {
test.skip('Default workspace name', async ({ page }) => { test('preset workspace name', async ({ page }) => {
const workspaceName = page.getByTestId('workspace-name'); const workspaceName = page.getByTestId('workspace-name');
expect(await workspaceName.textContent()).toBe('AFFiNE'); expect(await workspaceName.textContent()).toBe('AFFiNE Test');
}); });
test.skip('Default workspace avatar', async ({ page }) => { test('default workspace avatar', async ({ page }) => {
const workspaceAvatar = page.getByTestId('workspace-avatar'); const workspaceAvatar = page.getByTestId('workspace-avatar');
expect(await workspaceAvatar.innerHTML()).toBe( expect(
'<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg"><rect x="0.5" y="0.5" width="39" height="39" rx="19.5" stroke="#6880FF" fill="#FFF"></rect><path fillRule="evenodd" clipRule="evenodd" d="M18.6303 8.79688L11.2559 29.8393H15.5752L20.2661 15.2858L24.959 29.8393H29.2637L21.8881 8.79688H18.6303Z" fill="#6880FF"></path></svg>' await workspaceAvatar.locator('img').getAttribute('src')
); ).not.toBeNull();
}); });
}); });
+1 -2
View File
@@ -78,7 +78,7 @@ test.describe('Add new page in quick search', () => {
}); });
test.describe('Search and select', () => { test.describe('Search and select', () => {
test('Create a new page and search this page', async ({ page }) => { test.skip('Create a new page and search this page', async ({ page }) => {
await newPage(page); await newPage(page);
await openQuickSearchByShortcut(page); await openQuickSearchByShortcut(page);
await page.keyboard.insertText('test123456'); await page.keyboard.insertText('test123456');
@@ -88,7 +88,6 @@ test.describe('Search and select', () => {
await assertTitleTexts(page, 'test123456'); await assertTitleTexts(page, 'test123456');
await openQuickSearchByShortcut(page); await openQuickSearchByShortcut(page);
await page.keyboard.insertText('test123456'); await page.keyboard.insertText('test123456');
await page.waitForTimeout(300);
await assertResultList(page, ['test123456']); await assertResultList(page, ['test123456']);
await page.keyboard.press('Enter'); await page.keyboard.press('Enter');
await page.waitForTimeout(300); await page.waitForTimeout(300);
+4 -1
View File
@@ -17,7 +17,10 @@
"experimentalDecorators": true, "experimentalDecorators": true,
"baseUrl": ".", "baseUrl": ".",
"paths": { "paths": {
"@/*": ["src/*"] "@/*": ["src/*"],
"@affine/datacenter": ["packages/datacenter/src"],
"@affine/i18n": ["packages/i18n/src"],
"@affine/logger": ["packages/logger/src"]
} }
}, },
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],