mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-16 14:40:43 +03:00
chore: improve coverage of cypress (#5483)
This commit is contained in:
parent
3b72f90ca5
commit
b794f3894e
File diff suppressed because one or more lines are too long
@ -1 +1,80 @@
|
||||
[{"database_id":"037a985f-f369-4c4a-8011-620012850a68","created_at":"1713429700","views":["48c52cf7-bf98-43fa-96ad-b31aade9b071"]},{"database_id":"daea6aee-9365-4703-a8e2-a2fa6a07b214","created_at":"1714449533","views":["b6347acb-3174-4f0e-98e9-dcce07e5dbf7"]},{"database_id":"4c658817-20db-4f56-b7f9-0637a22dfeb6","created_at":"0","views":["7d2148fc-cace-4452-9c5c-96e52e6bf8b5","e410747b-5f2f-45a0-b2f7-890ad3001355","2143e95d-5dcb-4e0f-bb2c-50944e6e019f","a5566e49-f156-4168-9b2d-17926c5da329","135615fa-66f7-4451-9b54-d7e99445fca4","b4e77203-5c8b-48df-bbc5-2e1143eb0e61","a6af311f-cbc8-42c2-b801-7115619c3776"]},{"database_id":"4c658817-20db-4f56-b7f9-0637a22dfeb6","created_at":"0","views":["7d2148fc-cace-4452-9c5c-96e52e6bf8b5","e97877f5-c365-4025-9e6a-e590c4b19dbb","f0c59921-04ee-4971-995c-79b7fd8c00e2","7eb697cd-6a55-40bb-96ac-0d4a3bc924b2"]},{"database_id":"ee63da2b-aa2a-4d0b-aab0-59008635363a","created_at":"0","views":["2c1ee95a-1b09-4a1f-8d5e-501bc4861a9d","91ea7c08-f6b3-4b81-aa1e-d3664686186f"]},{"database_id":"e788f014-d0d3-4dfe-81ef-aa1ebb4d6366","created_at":"0","views":["1b0e322d-4909-4c63-914a-d034fc363097","350f425b-b671-4e2d-8182-5998a6e62924"]},{"database_id":"ad7dc45b-44b5-498f-bfa2-0f43bf05cc0d","created_at":"0","views":["0ce13415-6cce-4497-94c6-475ad96c249e","e4c89421-12b2-4d02-863d-20949eec9271"]},{"database_id":"ce267d12-3b61-4ebb-bb03-d65272f5f817","created_at":"0","views":["ee3ae8ce-959a-4df3-8734-40b535ff88e3","66a6f3bc-c78f-4f74-a09e-08d4717bf1fd","2bf50c03-f41f-4363-b5b1-101216a6c5cc"]}]
|
||||
[
|
||||
{
|
||||
"database_id": "037a985f-f369-4c4a-8011-620012850a68",
|
||||
"created_at": "1713429700",
|
||||
"views": [
|
||||
"48c52cf7-bf98-43fa-96ad-b31aade9b071"
|
||||
]
|
||||
},
|
||||
{
|
||||
"database_id": "daea6aee-9365-4703-a8e2-a2fa6a07b214",
|
||||
"created_at": "1714449533",
|
||||
"views": [
|
||||
"b6347acb-3174-4f0e-98e9-dcce07e5dbf7"
|
||||
]
|
||||
},
|
||||
{
|
||||
"database_id": "4c658817-20db-4f56-b7f9-0637a22dfeb6",
|
||||
"created_at": "0",
|
||||
"views": [
|
||||
"7d2148fc-cace-4452-9c5c-96e52e6bf8b5",
|
||||
"e410747b-5f2f-45a0-b2f7-890ad3001355",
|
||||
"2143e95d-5dcb-4e0f-bb2c-50944e6e019f",
|
||||
"a5566e49-f156-4168-9b2d-17926c5da329",
|
||||
"135615fa-66f7-4451-9b54-d7e99445fca4",
|
||||
"b4e77203-5c8b-48df-bbc5-2e1143eb0e61",
|
||||
"a6af311f-cbc8-42c2-b801-7115619c3776"
|
||||
]
|
||||
},
|
||||
{
|
||||
"database_id": "4c658817-20db-4f56-b7f9-0637a22dfeb6",
|
||||
"created_at": "0",
|
||||
"views": [
|
||||
"7d2148fc-cace-4452-9c5c-96e52e6bf8b5",
|
||||
"e97877f5-c365-4025-9e6a-e590c4b19dbb",
|
||||
"f0c59921-04ee-4971-995c-79b7fd8c00e2",
|
||||
"7eb697cd-6a55-40bb-96ac-0d4a3bc924b2"
|
||||
]
|
||||
},
|
||||
{
|
||||
"database_id": "ee63da2b-aa2a-4d0b-aab0-59008635363a",
|
||||
"created_at": "0",
|
||||
"views": [
|
||||
"2c1ee95a-1b09-4a1f-8d5e-501bc4861a9d",
|
||||
"91ea7c08-f6b3-4b81-aa1e-d3664686186f"
|
||||
]
|
||||
},
|
||||
{
|
||||
"database_id": "e788f014-d0d3-4dfe-81ef-aa1ebb4d6366",
|
||||
"created_at": "0",
|
||||
"views": [
|
||||
"1b0e322d-4909-4c63-914a-d034fc363097",
|
||||
"350f425b-b671-4e2d-8182-5998a6e62924"
|
||||
]
|
||||
},
|
||||
{
|
||||
"database_id": "ad7dc45b-44b5-498f-bfa2-0f43bf05cc0d",
|
||||
"created_at": "0",
|
||||
"views": [
|
||||
"0ce13415-6cce-4497-94c6-475ad96c249e",
|
||||
"e4c89421-12b2-4d02-863d-20949eec9271"
|
||||
]
|
||||
},
|
||||
{
|
||||
"database_id": "ce267d12-3b61-4ebb-bb03-d65272f5f817",
|
||||
"created_at": "0",
|
||||
"views": [
|
||||
"ee3ae8ce-959a-4df3-8734-40b535ff88e3",
|
||||
"66a6f3bc-c78f-4f74-a09e-08d4717bf1fd",
|
||||
"2bf50c03-f41f-4363-b5b1-101216a6c5cc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"database_id": "87bc006e-c1eb-47fd-9ac6-e39b17956369",
|
||||
"created_at": "0",
|
||||
"views": [
|
||||
"7f233be4-1b4d-46b2-bcfc-f341b8d75267",
|
||||
"a734a068-e73d-4b4b-853c-4daffea389c0"
|
||||
]
|
||||
}
|
||||
]
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -36,12 +36,36 @@ declare global {
|
||||
mockCurrentWorkspace: () => void;
|
||||
mockGetWorkspaceDatabases: () => void;
|
||||
mockDocument: (id: string) => void;
|
||||
clickOutside: () => void;
|
||||
getTestingSelector: (testId: string) => Chainable<JQuery<HTMLElement>>;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Cypress.Commands.add('mount', mount);
|
||||
|
||||
Cypress.Commands.add('getTestingSelector', (testId: string) => {
|
||||
return cy.get(`[data-testid="${testId}"]`);
|
||||
});
|
||||
|
||||
Cypress.Commands.add('clickOutside', () => {
|
||||
cy.document().then((doc) => {
|
||||
// [0, 0] is the top left corner of the window
|
||||
const x = 0;
|
||||
const y = 0;
|
||||
|
||||
const evt = new MouseEvent('click', {
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
view: window,
|
||||
clientX: x,
|
||||
clientY: y,
|
||||
});
|
||||
|
||||
// Dispatch the event
|
||||
doc.elementFromPoint(x, y)?.dispatchEvent(evt);
|
||||
});
|
||||
});
|
||||
// Example use:
|
||||
// cy.mount(<MyComponent />)
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { ViewLayout, YFolder, YjsFolderKey } from '@/application/collab.type';
|
||||
import { createContext, useCallback, useContext } from 'react';
|
||||
import { createContext, useContext } from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
|
||||
export interface Crumb {
|
||||
@ -36,14 +36,3 @@ export const useNavigateToView = () => {
|
||||
export const useCrumbs = () => {
|
||||
return useContext(FolderContext)?.crumbs;
|
||||
};
|
||||
|
||||
export const usePushCrumb = () => {
|
||||
const { setCrumbs } = useContext(FolderContext) || {};
|
||||
|
||||
return useCallback(
|
||||
(crumb: Crumb) => {
|
||||
setCrumbs?.((prevCrumbs) => [...prevCrumbs, crumb]);
|
||||
},
|
||||
[setCrumbs]
|
||||
);
|
||||
};
|
||||
|
@ -100,6 +100,7 @@ export async function batchCollabs(
|
||||
|
||||
const res = await batchFetchCollab(workspaceId, params);
|
||||
|
||||
console.log('Fetched collab data:', res);
|
||||
for (const id of Object.keys(res)) {
|
||||
const type = params.find((param) => param.object_id === id)?.collab_type;
|
||||
const data = res[id];
|
||||
|
@ -1,123 +0,0 @@
|
||||
import { YDoc, YFolder, YjsEditorKey } from '@/application/collab.type';
|
||||
import { applyYDoc } from '@/application/ydoc/apply';
|
||||
import { FolderProvider } from '@/components/_shared/context-provider/FolderProvider';
|
||||
import { IdProvider } from '@/components/_shared/context-provider/IdProvider';
|
||||
import withAppWrapper from '@/components/app/withAppWrapper';
|
||||
import { useState } from 'react';
|
||||
import { Database } from './Database';
|
||||
import { DatabaseContextProvider } from './DatabaseContext';
|
||||
import * as Y from 'yjs';
|
||||
import '@/components/layout/layout.scss';
|
||||
|
||||
describe('<Database />', () => {
|
||||
beforeEach(() => {
|
||||
cy.viewport(1280, 720);
|
||||
Object.defineProperty(window.navigator, 'language', { value: 'en-US' });
|
||||
Object.defineProperty(window.navigator, 'languages', { value: ['en-US'] });
|
||||
cy.mockDatabase();
|
||||
});
|
||||
|
||||
it('renders with a database', () => {
|
||||
cy.fixture('folder').then((folderJson) => {
|
||||
const doc = new Y.Doc();
|
||||
const state = new Uint8Array(folderJson.data.doc_state);
|
||||
|
||||
applyYDoc(doc, state);
|
||||
|
||||
const folder = doc.getMap(YjsEditorKey.data_section).get(YjsEditorKey.folder) as YFolder;
|
||||
|
||||
cy.fixture(`database/4c658817-20db-4f56-b7f9-0637a22dfeb6`).then((database) => {
|
||||
cy.fixture(`database/rows/4c658817-20db-4f56-b7f9-0637a22dfeb6`).then((rows) => {
|
||||
const doc = new Y.Doc();
|
||||
const rootRowsDoc = new Y.Doc();
|
||||
const rowsFolder: Y.Map<YDoc> = rootRowsDoc.getMap();
|
||||
const databaseState = new Uint8Array(database.data.doc_state);
|
||||
|
||||
applyYDoc(doc, databaseState);
|
||||
|
||||
Object.keys(rows).forEach((key) => {
|
||||
const data = rows[key];
|
||||
const rowDoc = new Y.Doc();
|
||||
|
||||
applyYDoc(rowDoc, new Uint8Array(data));
|
||||
rowsFolder.set(key, rowDoc);
|
||||
});
|
||||
|
||||
const onNavigateToView = cy.stub();
|
||||
|
||||
const AppWrapper = withAppWrapper(() => {
|
||||
return (
|
||||
<div className={'flex h-screen w-screen flex-col py-4'}>
|
||||
<TestDatabase
|
||||
databaseDoc={doc}
|
||||
rows={rowsFolder}
|
||||
folder={folder}
|
||||
iidIndex={'7d2148fc-cace-4452-9c5c-96e52e6bf8b5'}
|
||||
initialViewId={'7d2148fc-cace-4452-9c5c-96e52e6bf8b5'}
|
||||
onNavigateToView={onNavigateToView}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
cy.mount(<AppWrapper />);
|
||||
|
||||
cy.get('[data-testid^=view-tab-]').should('have.length', 4);
|
||||
cy.get('.database-grid').should('exist');
|
||||
|
||||
cy.get('[data-testid=view-tab-e410747b-5f2f-45a0-b2f7-890ad3001355]').click();
|
||||
cy.get('.database-board').should('exist');
|
||||
cy.wrap(onNavigateToView).should('have.been.calledOnceWith', 'e410747b-5f2f-45a0-b2f7-890ad3001355');
|
||||
|
||||
cy.wait(800);
|
||||
cy.get('[data-testid=view-tab-7d2148fc-cace-4452-9c5c-96e52e6bf8b5]').click();
|
||||
cy.get('.database-grid').should('exist');
|
||||
cy.wrap(onNavigateToView).should('have.been.calledWith', '7d2148fc-cace-4452-9c5c-96e52e6bf8b5');
|
||||
|
||||
cy.wait(800);
|
||||
cy.get('[data-testid=view-tab-2143e95d-5dcb-4e0f-bb2c-50944e6e019f]').click();
|
||||
cy.get('.database-calendar').should('exist');
|
||||
cy.wrap(onNavigateToView).should('have.been.calledWith', '2143e95d-5dcb-4e0f-bb2c-50944e6e019f');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function TestDatabase({
|
||||
databaseDoc,
|
||||
rows,
|
||||
folder,
|
||||
iidIndex,
|
||||
initialViewId,
|
||||
onNavigateToView,
|
||||
}: {
|
||||
databaseDoc: YDoc;
|
||||
rows: Y.Map<YDoc>;
|
||||
folder: YFolder;
|
||||
iidIndex: string;
|
||||
initialViewId: string;
|
||||
onNavigateToView: (viewId: string) => void;
|
||||
}) {
|
||||
const [activeViewId, setActiveViewId] = useState<string>(initialViewId);
|
||||
|
||||
const handleNavigateToView = (viewId: string) => {
|
||||
setActiveViewId(viewId);
|
||||
onNavigateToView(viewId);
|
||||
};
|
||||
|
||||
return (
|
||||
<FolderProvider folder={folder}>
|
||||
<IdProvider objectId={iidIndex}>
|
||||
<DatabaseContextProvider
|
||||
viewId={activeViewId || iidIndex}
|
||||
databaseDoc={databaseDoc}
|
||||
rowDocMap={rows}
|
||||
readOnly={true}
|
||||
>
|
||||
<Database iidIndex={iidIndex} viewId={activeViewId} onNavigateToView={handleNavigateToView} />
|
||||
</DatabaseContextProvider>
|
||||
</IdProvider>
|
||||
</FolderProvider>
|
||||
);
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
import { renderDatabase } from '@/components/database/__tests__/withTestingDatabase';
|
||||
import '@/components/layout/layout.scss';
|
||||
|
||||
describe('<Database />', () => {
|
||||
beforeEach(() => {
|
||||
cy.viewport(1280, 720);
|
||||
Object.defineProperty(window.navigator, 'language', { value: 'en-US' });
|
||||
cy.mockDatabase();
|
||||
});
|
||||
|
||||
it('renders with a database', () => {
|
||||
const onNavigateToView = cy.stub();
|
||||
|
||||
renderDatabase(
|
||||
{
|
||||
databaseId: '4c658817-20db-4f56-b7f9-0637a22dfeb6',
|
||||
viewId: '7d2148fc-cace-4452-9c5c-96e52e6bf8b5',
|
||||
onNavigateToView,
|
||||
},
|
||||
() => {
|
||||
cy.get('[data-testid^=view-tab-]').should('have.length', 4);
|
||||
cy.get('.database-grid').should('exist');
|
||||
|
||||
cy.get('[data-testid=view-tab-e410747b-5f2f-45a0-b2f7-890ad3001355]').click();
|
||||
cy.get('.database-board').should('exist');
|
||||
cy.wrap(onNavigateToView).should('have.been.calledOnceWith', 'e410747b-5f2f-45a0-b2f7-890ad3001355');
|
||||
|
||||
cy.wait(800);
|
||||
cy.get('[data-testid=view-tab-7d2148fc-cace-4452-9c5c-96e52e6bf8b5]').click();
|
||||
cy.get('.database-grid').should('exist');
|
||||
cy.wrap(onNavigateToView).should('have.been.calledWith', '7d2148fc-cace-4452-9c5c-96e52e6bf8b5');
|
||||
|
||||
cy.wait(800);
|
||||
cy.get('[data-testid=view-tab-2143e95d-5dcb-4e0f-bb2c-50944e6e019f]').click();
|
||||
cy.get('.database-calendar').should('exist');
|
||||
cy.wrap(onNavigateToView).should('have.been.calledWith', '2143e95d-5dcb-4e0f-bb2c-50944e6e019f');
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
@ -3,8 +3,8 @@ import { applyYDoc } from '@/application/ydoc/apply';
|
||||
import { FolderProvider } from '@/components/_shared/context-provider/FolderProvider';
|
||||
import { IdProvider } from '@/components/_shared/context-provider/IdProvider';
|
||||
import withAppWrapper from '@/components/app/withAppWrapper';
|
||||
import { DatabaseRow } from './DatabaseRow';
|
||||
import { DatabaseContextProvider } from './DatabaseContext';
|
||||
import { DatabaseRow } from 'src/components/database/DatabaseRow';
|
||||
import { DatabaseContextProvider } from 'src/components/database/DatabaseContext';
|
||||
import * as Y from 'yjs';
|
||||
import '@/components/layout/layout.scss';
|
||||
|
@ -0,0 +1,99 @@
|
||||
import { renderDatabase } from '@/components/database/__tests__/withTestingDatabase';
|
||||
import '@/components/layout/layout.scss';
|
||||
|
||||
describe('<Database /> with filters and sorts', () => {
|
||||
beforeEach(() => {
|
||||
cy.viewport(1280, 720);
|
||||
Object.defineProperty(window.navigator, 'language', { value: 'en-US' });
|
||||
cy.mockDatabase();
|
||||
});
|
||||
|
||||
it('render a database with filters and sorts', () => {
|
||||
const onNavigateToView = cy.stub();
|
||||
|
||||
renderDatabase(
|
||||
{
|
||||
onNavigateToView,
|
||||
databaseId: '87bc006e-c1eb-47fd-9ac6-e39b17956369',
|
||||
viewId: '7f233be4-1b4d-46b2-bcfc-f341b8d75267',
|
||||
},
|
||||
() => {
|
||||
cy.wait(1000);
|
||||
cy.getTestingSelector('database-actions-filter').click();
|
||||
|
||||
cy.get('.database-conditions').then(($el) => {
|
||||
cy.wait(500);
|
||||
const height = $el.height();
|
||||
|
||||
expect(height).to.be.greaterThan(0);
|
||||
});
|
||||
|
||||
cy.getTestingSelector('database-sort-condition').click();
|
||||
cy.wait(500);
|
||||
cy.getTestingSelector('sort-condition').as('sortConditions').should('have.length', 2);
|
||||
cy.get('@sortConditions').eq(0).contains('number');
|
||||
cy.get('@sortConditions').eq(0).contains('Ascending');
|
||||
cy.get('@sortConditions').eq(1).contains('Name');
|
||||
cy.get('@sortConditions').eq(1).contains('Descending');
|
||||
cy.clickOutside();
|
||||
cy.getTestingSelector('sort-condition-list').should('not.exist');
|
||||
|
||||
// the length of filters should be 6
|
||||
cy.getTestingSelector('database-filter-condition').as('filterConditions');
|
||||
cy.get('@filterConditions').should('have.length', 6);
|
||||
// the first filter should be 'Name', the value should be 'contains', and the input should be 123
|
||||
cy.get('@filterConditions').eq(0).as('filterCondition');
|
||||
cy.get('@filterCondition').contains('Name');
|
||||
cy.get('@filterCondition').contains('123');
|
||||
cy.get('@filterCondition').click();
|
||||
cy.getTestingSelector('filter-menu-popover').should('be.visible');
|
||||
cy.getTestingSelector('filter-condition-type').contains('Contains');
|
||||
cy.get(`[data-testid="text-filter-input"] input`).should('have.value', '123');
|
||||
cy.clickOutside();
|
||||
// the second filter should be 'Type', the value should be 'is not empty'
|
||||
cy.get('@filterConditions').eq(1).as('filterCondition');
|
||||
cy.get('@filterCondition').contains('Type');
|
||||
cy.get('@filterCondition').contains('is not empty');
|
||||
cy.get('@filterCondition').click();
|
||||
cy.clickOutside();
|
||||
// the third filter should be 'Done', the value should be 'is Checked'
|
||||
cy.get('@filterConditions').eq(2).as('filterCondition');
|
||||
cy.get('@filterCondition').contains('Done');
|
||||
cy.get('@filterCondition').contains('is Checked');
|
||||
cy.get('@filterCondition').click();
|
||||
cy.clickOutside();
|
||||
// the fourth filter should be 'Number', the value should be 'is greater than', and the input should be 600
|
||||
cy.get('@filterConditions').eq(3).as('filterCondition');
|
||||
cy.get('@filterCondition').contains('number');
|
||||
cy.get('@filterCondition').contains('> 600');
|
||||
cy.get('@filterCondition').click();
|
||||
cy.getTestingSelector('filter-menu-popover').should('be.visible');
|
||||
cy.getTestingSelector('filter-condition-type').contains('Is greater than');
|
||||
cy.get(`[data-testid="number-filter-input"] input`).should('have.value', '600');
|
||||
cy.clickOutside();
|
||||
// the fifth filter should be 'multi type', the value should be 'Does not contain'
|
||||
cy.get('@filterConditions').eq(4).as('filterCondition');
|
||||
cy.get('@filterCondition').contains('multi type');
|
||||
cy.get('@filterCondition').click();
|
||||
cy.getTestingSelector('filter-menu-popover').should('be.visible');
|
||||
cy.getTestingSelector('filter-condition-type').contains('Does not contain');
|
||||
cy.getTestingSelector('select-option-list').as('selectOptionList');
|
||||
cy.get('@selectOptionList').should('have.length', 2);
|
||||
cy.get('@selectOptionList').eq(0).contains('option-2');
|
||||
cy.get('@selectOptionList').eq(1).contains('option-1');
|
||||
cy.get('@selectOptionList').eq(1).should('have.data', 'checked', true);
|
||||
cy.clickOutside();
|
||||
// the sixth filter should be 'Checklist', the value should be 'is completed'
|
||||
cy.get('@filterConditions').eq(5).as('filterCondition');
|
||||
cy.get('@filterCondition').contains('Checklist');
|
||||
cy.get('@filterCondition').contains('is complete');
|
||||
cy.get('@filterCondition').click();
|
||||
cy.clickOutside();
|
||||
|
||||
cy.getTestingSelector('view-tab-a734a068-e73d-4b4b-853c-4daffea389c0').click();
|
||||
cy.wait(800);
|
||||
cy.getTestingSelector('view-tab-7f233be4-1b4d-46b2-bcfc-f341b8d75267').click();
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
@ -0,0 +1,106 @@
|
||||
import { YDoc, YFolder, YjsEditorKey } from '@/application/collab.type';
|
||||
import { applyYDoc } from '@/application/ydoc/apply';
|
||||
import { FolderProvider } from '@/components/_shared/context-provider/FolderProvider';
|
||||
import { IdProvider } from '@/components/_shared/context-provider/IdProvider';
|
||||
import withAppWrapper from '@/components/app/withAppWrapper';
|
||||
import { DatabaseContextProvider } from '@/components/database/DatabaseContext';
|
||||
import { useState } from 'react';
|
||||
import * as Y from 'yjs';
|
||||
import { Database } from 'src/components/database/Database';
|
||||
|
||||
export function renderDatabase(
|
||||
{
|
||||
databaseId,
|
||||
viewId,
|
||||
onNavigateToView,
|
||||
}: {
|
||||
databaseId: string;
|
||||
viewId: string;
|
||||
onNavigateToView: (viewId: string) => void;
|
||||
},
|
||||
onAfterRender?: () => void
|
||||
) {
|
||||
cy.fixture('folder').then((folderJson) => {
|
||||
const doc = new Y.Doc();
|
||||
const state = new Uint8Array(folderJson.data.doc_state);
|
||||
|
||||
applyYDoc(doc, state);
|
||||
|
||||
const folder = doc.getMap(YjsEditorKey.data_section).get(YjsEditorKey.folder) as YFolder;
|
||||
|
||||
cy.fixture(`database/${databaseId}`).then((database) => {
|
||||
cy.fixture(`database/rows/${databaseId}`).then((rows) => {
|
||||
const doc = new Y.Doc();
|
||||
const rootRowsDoc = new Y.Doc();
|
||||
const rowsFolder: Y.Map<YDoc> = rootRowsDoc.getMap();
|
||||
const databaseState = new Uint8Array(database.data.doc_state);
|
||||
|
||||
applyYDoc(doc, databaseState);
|
||||
|
||||
Object.keys(rows).forEach((key) => {
|
||||
const data = rows[key];
|
||||
const rowDoc = new Y.Doc();
|
||||
|
||||
applyYDoc(rowDoc, new Uint8Array(data));
|
||||
rowsFolder.set(key, rowDoc);
|
||||
});
|
||||
|
||||
const AppWrapper = withAppWrapper(() => {
|
||||
return (
|
||||
<div className={'flex h-screen w-screen flex-col py-4'}>
|
||||
<TestDatabase
|
||||
databaseDoc={doc}
|
||||
rows={rowsFolder}
|
||||
folder={folder}
|
||||
iidIndex={viewId}
|
||||
initialViewId={viewId}
|
||||
onNavigateToView={onNavigateToView}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
cy.mount(<AppWrapper />);
|
||||
onAfterRender?.();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function TestDatabase({
|
||||
databaseDoc,
|
||||
rows,
|
||||
folder,
|
||||
iidIndex,
|
||||
initialViewId,
|
||||
onNavigateToView,
|
||||
}: {
|
||||
databaseDoc: YDoc;
|
||||
rows: Y.Map<YDoc>;
|
||||
folder: YFolder;
|
||||
iidIndex: string;
|
||||
initialViewId: string;
|
||||
onNavigateToView: (viewId: string) => void;
|
||||
}) {
|
||||
const [activeViewId, setActiveViewId] = useState<string>(initialViewId);
|
||||
|
||||
const handleNavigateToView = (viewId: string) => {
|
||||
setActiveViewId(viewId);
|
||||
onNavigateToView(viewId);
|
||||
};
|
||||
|
||||
return (
|
||||
<FolderProvider folder={folder}>
|
||||
<IdProvider objectId={iidIndex}>
|
||||
<DatabaseContextProvider
|
||||
viewId={activeViewId || iidIndex}
|
||||
databaseDoc={databaseDoc}
|
||||
rowDocMap={rows}
|
||||
readOnly={true}
|
||||
>
|
||||
<Database iidIndex={iidIndex} viewId={activeViewId} onNavigateToView={handleNavigateToView} />
|
||||
</DatabaseContextProvider>
|
||||
</IdProvider>
|
||||
</FolderProvider>
|
||||
);
|
||||
}
|
@ -17,11 +17,13 @@ export function DatabaseActions() {
|
||||
onClick={() => {
|
||||
conditionsContext?.toggleExpanded();
|
||||
}}
|
||||
data-testid={'database-actions-filter'}
|
||||
color={filter.length > 0 ? 'primary' : 'inherit'}
|
||||
>
|
||||
{t('grid.settings.filter')}
|
||||
</TextButton>
|
||||
<TextButton
|
||||
data-testid={'database-actions-sort'}
|
||||
onClick={() => {
|
||||
conditionsContext?.toggleExpanded();
|
||||
}}
|
||||
|
@ -16,8 +16,13 @@ export function SelectOptionList({ fieldId, selectedIds }: { fieldId: string; se
|
||||
const isSelected = selectedIds.includes(option.id);
|
||||
|
||||
return (
|
||||
<div key={option.id} className={'flex items-center justify-between gap-2'}>
|
||||
<Tag label={option.name} color={SelectOptionColorMap[option.color]} />
|
||||
<div
|
||||
key={option.id}
|
||||
data-testid={'select-option-list'}
|
||||
data-checked={isSelected}
|
||||
className={'flex items-center justify-between gap-2 text-xs'}
|
||||
>
|
||||
<Tag size={'small'} label={option.name} color={SelectOptionColorMap[option.color]} />
|
||||
{isSelected && <CheckIcon />}
|
||||
</div>
|
||||
);
|
||||
|
@ -19,6 +19,7 @@ function Filter({ filterId }: { filterId: string }) {
|
||||
onClick={(e) => {
|
||||
setAnchorEl(e.currentTarget);
|
||||
}}
|
||||
data-testid={'database-filter-condition'}
|
||||
className={
|
||||
'flex cursor-pointer flex-nowrap items-center gap-1 rounded-full border border-line-divider py-1 px-2 hover:border-fill-default hover:text-fill-default hover:shadow-sm'
|
||||
}
|
||||
@ -39,6 +40,7 @@ function Filter({ filterId }: { filterId: string }) {
|
||||
onClose={() => {
|
||||
setAnchorEl(null);
|
||||
}}
|
||||
data-testid={'filter-menu-popover'}
|
||||
slotProps={{
|
||||
paper: {
|
||||
style: {
|
||||
|
@ -10,7 +10,10 @@ function FieldMenuTitle({ fieldId, selectedConditionText }: { fieldId: string; s
|
||||
</div>
|
||||
<div className={'flex flex-1 items-center justify-end'}>
|
||||
<div className={'flex items-center gap-1'}>
|
||||
<div className={'overflow max-w-[100px] truncate whitespace-nowrap text-xs font-normal'}>
|
||||
<div
|
||||
data-testid={'filter-condition-type'}
|
||||
className={'overflow max-w-[100px] truncate whitespace-nowrap text-xs font-normal'}
|
||||
>
|
||||
{selectedConditionText}
|
||||
</div>
|
||||
<ArrowDownSvg />
|
||||
|
@ -58,6 +58,7 @@ function NumberFilterMenu({ filter }: { filter: NumberFilter }) {
|
||||
{displayTextField && (
|
||||
<TextField
|
||||
disabled={readOnly}
|
||||
data-testid={'number-filter-input'}
|
||||
spellCheck={false}
|
||||
inputProps={{
|
||||
className: 'text-xs p-1.5',
|
||||
|
@ -53,10 +53,11 @@ function TextFilterMenu({ filter }: { filter: TextFilter }) {
|
||||
}, [filter.condition]);
|
||||
|
||||
return (
|
||||
<div className={'flex flex-col gap-2 p-2'}>
|
||||
<div className={'flex flex-col gap-2 p-2'} data-testid='text-filter'>
|
||||
<FieldMenuTitle fieldId={filter.fieldId} selectedConditionText={selectedCondition?.text ?? ''} />
|
||||
{displayTextField && (
|
||||
<TextField
|
||||
data-testid='text-filter-input'
|
||||
disabled={readOnly}
|
||||
spellCheck={false}
|
||||
inputProps={{
|
||||
|
@ -8,7 +8,7 @@ function Sort({ sortId }: { sortId: string }) {
|
||||
|
||||
if (!sort) return null;
|
||||
return (
|
||||
<div className={'flex items-center gap-1.5'}>
|
||||
<div data-testid={'sort-condition'} className={'flex items-center gap-1.5'}>
|
||||
<div className={'w-[120px] max-w-[250px] overflow-hidden rounded-full border border-line-divider py-1 px-2 '}>
|
||||
<FieldDisplay fieldId={sort.fieldId} />
|
||||
</div>
|
||||
|
@ -19,6 +19,7 @@ export function Sorts() {
|
||||
onClick={(e) => {
|
||||
setAnchorEl(e.currentTarget);
|
||||
}}
|
||||
data-testid={'database-sort-condition'}
|
||||
className='flex cursor-pointer items-center gap-1 rounded-full border border-line-divider px-2 py-1 text-xs hover:border-fill-default hover:text-fill-default hover:shadow-sm'
|
||||
>
|
||||
<SortSvg />
|
||||
|
@ -73,7 +73,7 @@ export function useLayout() {
|
||||
return {
|
||||
viewId: view.get(YjsFolderKey.id),
|
||||
name: view.get(YjsFolderKey.name),
|
||||
icon: icon || '',
|
||||
icon: icon || view.get(YjsFolderKey.layout),
|
||||
};
|
||||
})
|
||||
.slice(1)
|
||||
|
@ -1,6 +1,31 @@
|
||||
import { ViewLayout } from '@/application/collab.type';
|
||||
import { Crumb, useNavigateToView } from '@/application/folder-yjs';
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { ReactComponent as DocumentSvg } from '$icons/16x/document.svg';
|
||||
import { ReactComponent as GridSvg } from '$icons/16x/grid.svg';
|
||||
import { ReactComponent as BoardSvg } from '$icons/16x/board.svg';
|
||||
import { ReactComponent as CalendarSvg } from '$icons/16x/date.svg';
|
||||
|
||||
const renderCrumbIcon = (icon: string) => {
|
||||
if (Number(icon) === ViewLayout.Grid) {
|
||||
return <GridSvg />;
|
||||
}
|
||||
|
||||
if (Number(icon) === ViewLayout.Board) {
|
||||
return <BoardSvg />;
|
||||
}
|
||||
|
||||
if (Number(icon) === ViewLayout.Calendar) {
|
||||
return <CalendarSvg />;
|
||||
}
|
||||
|
||||
if (Number(icon) === ViewLayout.Document) {
|
||||
return <DocumentSvg />;
|
||||
}
|
||||
|
||||
return icon;
|
||||
};
|
||||
|
||||
function Item({ crumb, disableClick = false }: { crumb: Crumb; disableClick?: boolean }) {
|
||||
const { viewId, icon, name } = crumb;
|
||||
@ -16,7 +41,7 @@ function Item({ crumb, disableClick = false }: { crumb: Crumb; disableClick?: bo
|
||||
onNavigateToView?.(viewId);
|
||||
}}
|
||||
>
|
||||
{icon}
|
||||
<span className={'h-4 w-4'}>{renderCrumbIcon(icon)}</span>
|
||||
<span
|
||||
className={!disableClick ? 'max-w-[250px] truncate hover:text-fill-default hover:underline' : 'flex-1 truncate'}
|
||||
>
|
||||
|
@ -78,7 +78,7 @@ export default defineConfig({
|
||||
port: !!process.env.TAURI_PLATFORM ? 5173 : process.env.PORT ? parseInt(process.env.PORT) : 3000,
|
||||
strictPort: true,
|
||||
watch: {
|
||||
ignored: ['**/__tests__/**', '**/cypress/**', 'node_modules', '**/*.cy.tsx', '**/*.cy.ts', 'cypress'],
|
||||
ignored: ['node_modules'],
|
||||
},
|
||||
cors: false,
|
||||
},
|
||||
@ -143,6 +143,10 @@ export default defineConfig({
|
||||
'@mui/icons-material/ErrorOutline',
|
||||
'@mui/icons-material/CheckCircleOutline',
|
||||
'@mui/icons-material/FunctionsOutlined',
|
||||
'react-katex',
|
||||
// 'react-custom-scrollbars-2',
|
||||
// 'react-window',
|
||||
// 'react-virtualized-auto-sizer',
|
||||
],
|
||||
},
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user