Skip to content

Commit

Permalink
Add E2E test for article export
Browse files Browse the repository at this point in the history
Partially resolves: Add E2E and component tests #33
  • Loading branch information
GodHermit committed Jul 24, 2023
1 parent 312027d commit ff5ef94
Show file tree
Hide file tree
Showing 16 changed files with 574 additions and 3 deletions.
19 changes: 19 additions & 0 deletions cypress.config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { defineConfig } from "cypress";
import { existsSync, rmdir } from 'fs';

export default defineConfig({
component: {
Expand All @@ -12,6 +13,24 @@ export default defineConfig({
baseUrl: "http://localhost:3000",
setupNodeEvents(on, config) {
// implement node event listeners here
on('task', {
deleteFolder(folderName) {
console.log('deleting folder %s', folderName)

return new Promise((resolve, reject) => {
if(existsSync(folderName) === false) {
resolve('Folder does not exist')
}
rmdir(folderName, { maxRetries: 10, recursive: true }, (err) => {
if (err) {
console.error(err)
return reject(err)
}
resolve(null)
})
})
},
})
},
},
});
279 changes: 279 additions & 0 deletions cypress/e2e/exportArticles.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,279 @@
import JSZip from 'jszip';
import path from 'path';

type ExportType = 'current' | 'all-in-one' | 'all-separated';
type ExportFormat = 'html' | 'md';

function execTest(
exportType: ExportType,
exportFormat: ExportFormat,
embeddedMedia: boolean,
fileAssertionOptions?: {
filename: string;
fixtureFilename: string;
}
) {
cy
.get('@exportType')
.should('have.value', exportType);

cy
.get('@exportFormat')
.should('have.value', exportFormat);

cy
.get('@exportEmbeddedMedia')
.should(embeddedMedia ? 'be.checked' : 'not.be.checked');

cy
.get('@exportButton')
.click(); // Click on export button

cy
.readFile(
path.join(Cypress.config('downloadsFolder'), fileAssertionOptions?.filename ?? '1. Introduction.html'),
{
timeout: 10000,
}
)
.as('exportedFile');

cy
.fixture(`exportArticles/${exportFormat}/${fileAssertionOptions?.fixtureFilename ?? '1. Introduction.html'}`)
.then((file) => {
cy
.get('@exportedFile')
.should(
'include',
exportFormat === 'html' ? file.replaceAll(/\t|\n|\r/g, '') : file.replaceAll(/\r/g, '')
);
});
};

function exportConfig(
exportType: ExportType,
exportFormat: ExportFormat,
embeddedMedia: boolean
) {
cy
.get('@exportType')
.select(exportType)
.should('have.value', exportType);

cy
.get('@exportFormat')
.select(exportFormat)
.should('have.value', exportFormat);

if (!embeddedMedia) {
cy
.get('@exportEmbeddedMedia')
.parent()
.click(); // Uncheck the embedded media option
}

cy
.get('@exportEmbeddedMedia')
.should(embeddedMedia ? 'be.checked' : 'not.be.checked');
}

describe('Export articles', () => {
beforeEach(() => {
cy.task('deleteFolder', Cypress.config('downloadsFolder')) // Delete the downloads folder before each test

cy
.intercept('/api/articles?locale=en&metadataOnly=true', {
fixture: 'articles.json',
})
.as('getArticles'); // Intercept the request to get the articles

cy
.intercept('/api/articlesMedia?locale=en', {
body: ['/wiki/assets/media.jpg'],
})

cy
.intercept('/wiki/en/1.%20Introduction.md', {
fixture: 'wiki/1. Introduction.md'
});

cy
.intercept('/wiki/assets/media.jpg', {
fixture: 'wiki/media.jpg'
});

cy.visit('/en'); // Visit the home page

cy
.wait('@getArticles')
.its('response.statusCode')
.should('eq', 200); // Wait for the request to finish

cy
.get('button[aria-label="More options"]')
.click(); // Open more options menu

cy
.findAllByRole('menuitem')
.findAllByText('Export')
.parent()
.click(); // Click on export option

cy.wait(500); // Wait for the modal to open

cy
.get('header')
.findByText('Export')
.parent()
.as('exportModal')
.should('be.visible')
.and('have.css', 'opacity', '1'); // Check that the modal is visible

cy
.findByLabelText('Export type')
.as('exportType'); // Get the export type select

cy
.findByLabelText('File format')
.as('exportFormat'); // Get the export format select

cy
.findByLabelText('Embed media')
.as('exportEmbeddedMedia'); // Get the export embedded media checkbox

cy
.get('@exportModal')
.find('button')
.contains('Export')
.as('exportButton') // Get the export button
.should('not.be.disabled');
});

it('Test default values', () => {
cy
.get('@exportType')
.should('have.value', 'current');

cy
.get('@exportFormat')
.should('have.value', 'html');

cy
.get('@exportEmbeddedMedia')
.should('be.checked');
});

context('Export current article', () => {
afterEach(() => {
cy.task('deleteFolder', Cypress.config('downloadsFolder')) // Delete the downloads folder after each test
});

const exportType = 'current';
const exportFormats: ExportFormat[] = ['html', 'md'];

for (const exportFormat of exportFormats) {
context(`As ${exportFormat}`, () => {
it('With embedded media', () => {
exportConfig(exportType, exportFormat, true);

execTest(exportType, exportFormat, true, {
filename: `1. Introduction.${exportFormat}`,
fixtureFilename: `1. Introduction.media.${exportFormat}`,
});
});

it('Without embedded media', () => {
exportConfig(exportType, exportFormat, false);

execTest(exportType, exportFormat, false, {
filename: `1. Introduction.${exportFormat}`,
fixtureFilename: `1. Introduction.${exportFormat}`,
});
});
});
}
});

context('Export all articles in one file', () => {
afterEach(() => {
cy.task('deleteFolder', Cypress.config('downloadsFolder')) // Delete the downloads folder after each test
});

const exportType = 'all-in-one';
const exportFormats: ExportFormat[] = ['html', 'md'];

for (const exportFormat of exportFormats) {
context(`As ${exportFormat}`, () => {
it('With embedded media', () => {
exportConfig(exportType, exportFormat, true);

execTest(exportType, exportFormat, true, {
filename: `Survival Manual.${exportFormat}`,
fixtureFilename: `Survival Manual.media.${exportFormat}`,
});
});

it('Without embedded media', () => {
exportConfig(exportType, exportFormat, false);

execTest(exportType, exportFormat, false, {
filename: `Survival Manual.${exportFormat}`,
fixtureFilename: `Survival Manual.${exportFormat}`,
});
});
});
}
});

context('Export all articles separated (in archive)', () => {
afterEach(() => {
cy.task('deleteFolder', Cypress.config('downloadsFolder')) // Delete the downloads folder after each test
});

const exportType = 'all-separated';
const exportFormats: ExportFormat[] = ['html', 'md'];

for (const exportFormat of exportFormats) {

it(`As archive with .${exportFormat} files`, () => {
cy
.get('@exportType')
.select(exportType)
.should('have.value', exportType);

cy
.get('@exportFormat')
.select(exportFormat)
.should('have.value', exportFormat);

cy
.get('@exportEmbeddedMedia')
.should('not.be.checked')
.and('be.disabled');

cy
.get('@exportButton')
.click(); // Click on export button

cy
.readFile(
path.join(Cypress.config('downloadsFolder'), 'Survival manual.zip'),
null,
{
timeout: 10000,
}
)
.then((file) => {
const expectedFiles = [
`1. Introduction.${exportFormat}`,
'assets/',
'assets/media.jpg'
];
JSZip.loadAsync(file).then(async (zip) => {
expect(zip.files).to.have.all.keys(expectedFiles);
});
});
});
}
});
});
14 changes: 14 additions & 0 deletions cypress/fixtures/exportArticles/html/1. Introduction.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<html>

<head>
<title>Introduction</title>
<meta charset='utf-8' />
<meta name='viewport' content='width=device-width, initial-scale=1.0' />
</head>

<body>
<h1>Introduction</h1>
<p><img src="http://localhost:3000/wiki/assets/media.jpg" alt="test media"></p>
</body>

</html>
15 changes: 15 additions & 0 deletions cypress/fixtures/exportArticles/html/1. Introduction.media.html

Large diffs are not rendered by default.

15 changes: 15 additions & 0 deletions cypress/fixtures/exportArticles/html/Survival Manual.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<html>

<head>
<title>Survival Manual</title>
<meta charset='utf-8' />
<meta name='viewport' content='width=device-width, initial-scale=1.0' />
<meta name='description' content='metadata.description' />
</head>

<body>
<h1>Introduction</h1>
<p><img src="http://localhost:3000/wiki/assets/media.jpg" alt="test media"></p>
</body>

</html>
16 changes: 16 additions & 0 deletions cypress/fixtures/exportArticles/html/Survival Manual.media.html

Large diffs are not rendered by default.

Binary file not shown.
3 changes: 3 additions & 0 deletions cypress/fixtures/exportArticles/md/1. Introduction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Introduction

![test media](http://localhost:3000/wiki/assets/media.jpg)
3 changes: 3 additions & 0 deletions cypress/fixtures/exportArticles/md/1. Introduction.media.md

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions cypress/fixtures/exportArticles/md/Survival Manual.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Introduction

![test media](http://localhost:3000/wiki/assets/media.jpg)
3 changes: 3 additions & 0 deletions cypress/fixtures/exportArticles/md/Survival Manual.media.md

Large diffs are not rendered by default.

Binary file not shown.
9 changes: 9 additions & 0 deletions cypress/fixtures/wiki/1. Introduction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
name: Introduction
icon: MdInfo
slug: /
---

# Introduction

![test media](/wiki/assets/media.jpg)
Binary file added cypress/fixtures/wiki/media.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit ff5ef94

Please sign in to comment.