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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ and this project adheres to
- ✨(backend) allow masking documents from the list view #1171
- ✨(frontend) subdocs can manage link reach #1190
- ✨(frontend) add duplicate action to doc tree #1175
- ✨(frontend) Interlinking doc #904
- ✨(frontend) add multi columns support for editor #1219

### Changed
Expand Down
44 changes: 44 additions & 0 deletions src/frontend/apps/e2e/__tests__/app-impress/doc-create.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,50 @@ test.describe('Doc Create', () => {
await expect(page.getByTestId('grid-loader')).toBeHidden();
await expect(docsGrid.getByText(docTitle)).toBeVisible();
});

test('it creates a sub doc from slash menu editor', async ({
page,
browserName,
}) => {
const [title] = await createDoc(page, 'my-new-slash-doc', browserName, 1);

await verifyDocName(page, title);

await page.locator('.bn-block-outer').last().fill('/');
await page
.getByText('New sub-doc', {
exact: true,
})
.click();

const input = page.getByRole('textbox', { name: 'doc title input' });
await expect(input).toHaveText('');
await expect(
page.locator('.c__tree-view--row-content').getByText('Untitled document'),
).toBeVisible();
});

test('it creates a sub doc from interlinking dropdown', async ({
page,
browserName,
}) => {
const [title] = await createDoc(page, 'my-new-slash-doc', browserName, 1);

await verifyDocName(page, title);

await page.locator('.bn-block-outer').last().fill('/');
await page.getByText('Link a doc').first().click();
await page
.locator('.quick-search-container')
.getByText('New sub-doc')
.click();

const input = page.getByRole('textbox', { name: 'doc title input' });
await expect(input).toHaveText('');
await expect(
page.locator('.c__tree-view--row-content').getByText('Untitled document'),
).toBeVisible();
});
});

test.describe('Doc Create: Not logged', () => {
Expand Down
71 changes: 71 additions & 0 deletions src/frontend/apps/e2e/__tests__/app-impress/doc-editor.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -706,4 +706,75 @@ test.describe('Doc Editor', () => {
'pink',
);
});

test('it checks interlink feature', async ({ page, browserName }) => {
const [randomDoc] = await createDoc(page, 'doc-interlink', browserName, 1);

await verifyDocName(page, randomDoc);

const { name: docChild1 } = await createRootSubPage(
page,
browserName,
'doc-interlink-child-1',
);

await verifyDocName(page, docChild1);

const { name: docChild2 } = await createRootSubPage(
page,
browserName,
'doc-interlink-child-2',
);

await verifyDocName(page, docChild2);

await page.locator('.bn-block-outer').last().fill('/');
await page.getByText('Link a doc').first().click();

const input = page.locator(
"span[data-inline-content-type='interlinkingSearchInline'] input",
);
const searchContainer = page.locator('.quick-search-container');

await input.fill('doc-interlink');

await expect(searchContainer.getByText(randomDoc)).toBeVisible();
await expect(searchContainer.getByText(docChild1)).toBeVisible();
await expect(searchContainer.getByText(docChild2)).toBeVisible();

await input.pressSequentially('-child');

await expect(searchContainer.getByText(docChild1)).toBeVisible();
await expect(searchContainer.getByText(docChild2)).toBeVisible();
await expect(searchContainer.getByText(randomDoc)).toBeHidden();

// use keydown to select the second result
await page.keyboard.press('ArrowDown');
await page.keyboard.press('Enter');

const interlink = page.getByRole('link', {
name: 'child-2',
});

await expect(interlink).toBeVisible();
await interlink.click();

await verifyDocName(page, docChild2);
});

test('it checks interlink shortcut @', async ({ page, browserName }) => {
const [randomDoc] = await createDoc(page, 'doc-interlink', browserName, 1);

await verifyDocName(page, randomDoc);

const editor = page.locator('.bn-block-outer').last();
await editor.click();
await page.keyboard.press('@');

await expect(
page.locator(
"span[data-inline-content-type='interlinkingSearchInline'] input",
),
).toBeVisible();
});
});
69 changes: 69 additions & 0 deletions src/frontend/apps/e2e/__tests__/app-impress/doc-export.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import cs from 'convert-stream';
import pdf from 'pdf-parse';

import { createDoc, verifyDocName } from './utils-common';
import { createRootSubPage } from './utils-sub-pages';

test.beforeEach(async ({ page }) => {
await page.goto('/');
Expand Down Expand Up @@ -411,4 +412,72 @@ test.describe('Doc Export', () => {
expect(pdfData.text).toContain('Column 2');
expect(pdfData.text).toContain('Column 3');
});

test('it exports the doc with interlinking', async ({
page,
browserName,
}) => {
const [randomDoc] = await createDoc(
page,
'export-interlinking',
browserName,
1,
);

await verifyDocName(page, randomDoc);

const { name: docChild } = await createRootSubPage(
page,
browserName,
'export-interlink-child',
);

await verifyDocName(page, docChild);

await page.locator('.bn-block-outer').last().fill('/');
await page.getByText('Link a doc').first().click();

await page
.locator(
"span[data-inline-content-type='interlinkingSearchInline'] input",
)
.fill('interlink-child');

await page
.locator('.quick-search-container')
.getByText('interlink-child')
.click();

const interlink = page.getByRole('link', {
name: 'interlink-child',
});

await expect(interlink).toBeVisible();

const downloadPromise = page.waitForEvent('download', (download) => {
return download.suggestedFilename().includes(`${docChild}.pdf`);
});

await page
.getByRole('button', {
name: 'download',
exact: true,
})
.click();

void page
.getByRole('button', {
name: 'Download',
exact: true,
})
.click();

const download = await downloadPromise;
expect(download.suggestedFilename()).toBe(`${docChild}.pdf`);

const pdfBuffer = await cs.toBuffer(await download.createReadStream());
const pdfData = await pdf(pdfBuffer);

expect(pdfData.text).toContain('interlink-child'); // This is the pdf text
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ test.describe('Doc grid dnd mobile', () => {
await expect(docsGrid.getByRole('row').first()).toBeVisible();
await expect(docsGrid.locator('.--docs--grid-droppable')).toHaveCount(0);

await createDoc(page, 'Draggable doc mobile', browserName, 1, false, true);
await createDoc(page, 'Draggable doc mobile', browserName, 1, true);

await createRootSubPage(
page,
Expand Down
17 changes: 5 additions & 12 deletions src/frontend/apps/e2e/__tests__/app-impress/doc-routing.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,11 @@ test.describe('Doc Routing', () => {
await page.goto('/');
});

test('Check the presence of the meta tag noindex', async ({ page }) => {
const buttonCreateHomepage = page.getByRole('button', {
name: 'New doc',
});

await expect(buttonCreateHomepage).toBeVisible();
await buttonCreateHomepage.click();
await expect(
page.getByRole('button', {
name: 'Share',
}),
).toBeVisible();
test('Check the presence of the meta tag noindex', async ({
page,
browserName,
}) => {
await createDoc(page, 'doc-routing-test', browserName, 1);
const metaDescription = page.locator('meta[name="robots"]');
await expect(metaDescription).toHaveAttribute('content', 'noindex');
});
Expand Down
6 changes: 0 additions & 6 deletions src/frontend/apps/e2e/__tests__/app-impress/utils-common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,17 +78,11 @@ export const createDoc = async (
docName: string,
browserName: string,
length: number = 1,
isChild: boolean = false,
isMobile: boolean = false,
) => {
const randomDocs = randomName(docName, browserName, length);

for (let i = 0; i < randomDocs.length; i++) {
if (!isChild && !isMobile) {
const header = page.locator('header').first();
await header.locator('h2').getByText('Docs').click();
}

if (isMobile) {
await page
.getByRole('button', { name: 'Open the header menu' })
Expand Down
9 changes: 5 additions & 4 deletions src/frontend/apps/impress/src/components/Box.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export interface BoxProps {
$background?: CSSProperties['background'];
$color?: CSSProperties['color'];
$css?: string | RuleSet<object>;
$cursor?: CSSProperties['cursor'];
$direction?: CSSProperties['flexDirection'];
$display?: CSSProperties['display'];
$effect?: 'show' | 'hide';
Expand Down Expand Up @@ -44,13 +45,13 @@ export interface BoxProps {
export type BoxType = ComponentPropsWithRef<typeof Box>;

export const Box = styled('div')<BoxProps>`
display: flex;
flex-direction: column;
${({ $align }) => $align && `align-items: ${$align};`}
${({ $background }) => $background && `background: ${$background};`}
${({ $color }) => $color && `color: ${$color};`}
${({ $direction }) => $direction && `flex-direction: ${$direction};`}
${({ $display }) => $display && `display: ${$display};`}
${({ $cursor }) => $cursor && `cursor: ${$cursor};`}
${({ $direction }) => `flex-direction: ${$direction || 'column'};`}
${({ $display, as }) =>
`display: ${$display || as?.match('span|input') ? 'inline-flex' : 'flex'};`}
${({ $flex }) => $flex && `flex: ${$flex};`}
${({ $gap }) => $gap && `gap: ${$gap};`}
${({ $height }) => $height && `height: ${$height};`}
Expand Down
2 changes: 1 addition & 1 deletion src/frontend/apps/impress/src/components/BoxButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@ const BoxButton = forwardRef<HTMLDivElement, BoxButtonType>(
$background="none"
$margin="none"
$padding="none"
$hasTransition
$css={css`
cursor: ${props.disabled ? 'not-allowed' : 'pointer'};
border: none;
outline: none;
transition: all 0.2s ease-in-out;
font-family: inherit;

color: ${props.disabled
Expand Down
4 changes: 3 additions & 1 deletion src/frontend/apps/impress/src/components/DropdownMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export type DropdownMenuProps = {
arrowCss?: BoxProps['$css'];
buttonCss?: BoxProps['$css'];
disabled?: boolean;
opened?: boolean;
topMessage?: string;
selectedValues?: string[];
afterOpenChange?: (isOpen: boolean) => void;
Expand All @@ -38,12 +39,13 @@ export const DropdownMenu = ({
arrowCss,
buttonCss,
label,
opened,
topMessage,
afterOpenChange,
selectedValues,
}: PropsWithChildren<DropdownMenuProps>) => {
const { spacingsTokens, colorsTokens } = useCunninghamTheme();
const [isOpen, setIsOpen] = useState(false);
const [isOpen, setIsOpen] = useState(opened ?? false);
const blockButtonRef = useRef<HTMLDivElement>(null);

const onOpenChange = (isOpen: boolean) => {
Expand Down
1 change: 1 addition & 0 deletions src/frontend/apps/impress/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export * from './BoxButton';
export * from './Card';
export * from './DropButton';
export * from './DropdownMenu';
export * from './quick-search';
export * from './Icon';
export * from './InfiniteScroll';
export * from './Link';
Expand Down
Loading
Loading