Skip to content

Commit

Permalink
Add some file system tests (#34)
Browse files Browse the repository at this point in the history
* Add some file system tests

* Correctly await ContentsHelper calls

* Skip rm test as not reliable for files that were added via --contents
  • Loading branch information
ianthomas23 authored Nov 8, 2024
1 parent f97824b commit f943371
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 19 deletions.
77 changes: 77 additions & 0 deletions ui-tests/tests/fs.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { expect, test } from '@jupyterlab/galata';

import { ContentsHelper } from './utils/contents';
import { TERMINAL_SELECTOR, decode64, inputLine } from './utils/misc';

const MONTHS_TXT =
'January\nFebruary\nMarch\nApril\nMay\nJune\nJuly\nAugust\nSeptember\nOctober\nNovember\nDecember\n';
const FACT_LUA =
'function fact(n, acc)\n' +
' acc = acc or 1\n' +
' if n == 0 then\n' +
' return acc\n' +
' end\n' +
' return fact(n-1, n*acc)\n' +
'end\n' +
'print(fact(tonumber(arg[1])))\n';

test.describe('Filesystem', () => {
test.beforeEach(async ({ page }) => {
await page.goto();

// Overwrite the (read-only) page.contents with our own ContentsHelper.
// @ts-ignore
page.contents = new ContentsHelper(page);

await page.menu.clickMenuItem('File>New>Terminal');
await page.locator(TERMINAL_SELECTOR).waitFor();
await page.locator('div.xterm-screen').click(); // sets focus for keyboard input
});

test('should have initial files', async ({ page }) => {
// Directory contents.
const content = await page.contents.getContentMetadata('', 'directory');
expect(content).not.toBeNull();
const filenames = content?.content.map(item => item.name);
expect(filenames).toEqual(
expect.arrayContaining(['fact.lua', 'months.txt'])
);

// File contents.
const months = await page.contents.getContentMetadata('months.txt');
expect(months?.content).toEqual(MONTHS_TXT);

// Note fact.lua contents are returned base64 encoded.
const fact = await page.contents.getContentMetadata('fact.lua');
expect(decode64(fact?.content)).toEqual(FACT_LUA);
});

test('should support cp', async ({ page }) => {
await inputLine(page, 'cp months.txt other.txt');
await page.filebrowser.refresh();

expect(await page.contents.fileExists('months.txt')).toBeTruthy();
expect(await page.contents.fileExists('other.txt')).toBeTruthy();

Check failure on line 54 in ui-tests/tests/fs.spec.ts

View workflow job for this annotation

GitHub Actions / Integration tests

tests/fs.spec.ts:49:7 › Filesystem › should support cp

1) tests/fs.spec.ts:49:7 › Filesystem › should support cp ──────────────────────────────────────── Error: expect(received).toBeTruthy() Received: false 52 | 53 | expect(await page.contents.fileExists('months.txt')).toBeTruthy(); > 54 | expect(await page.contents.fileExists('other.txt')).toBeTruthy(); | ^ 55 | 56 | const other = await page.contents.getContentMetadata('other.txt'); 57 | expect(other?.content).toEqual(MONTHS_TXT); at /home/runner/work/terminal/terminal/ui-tests/tests/fs.spec.ts:54:57

const other = await page.contents.getContentMetadata('other.txt');
expect(other?.content).toEqual(MONTHS_TXT);
});

// rm of files added via --contents is not reliable.
test.skip('should support rm', async ({ page }) => {
await inputLine(page, 'rm fact.lua');
await page.filebrowser.refresh();

expect(await page.contents.fileExists('fact.lua')).toBeFalsy();
});

test('should support touch', async ({ page }) => {
await inputLine(page, 'touch touched.txt');
await page.filebrowser.refresh();

expect(await page.contents.fileExists('touched.txt')).toBeTruthy();

const other = await page.contents.getContentMetadata('touched.txt');
expect(other?.content).toEqual('');
});
});
27 changes: 8 additions & 19 deletions ui-tests/tests/jupyterlite_terminal.spec.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,5 @@
import { expect, test } from '@jupyterlab/galata';

const TERMINAL_SELECTOR = '.jp-Terminal';

async function inputLine(page, text: string) {
for (const char of text) {
await page.keyboard.type(char);
await page.waitForTimeout(10);
}
await page.keyboard.press('Enter');
}
import { TERMINAL_SELECTOR, WAIT_MS, inputLine } from './utils/misc';

test.describe('Terminal extension', () => {
test('should emit activation console messages', async ({ page }) => {
Expand Down Expand Up @@ -82,28 +73,26 @@ test.describe('Images', () => {
await page.locator(TERMINAL_SELECTOR).waitFor();
await page.locator('div.xterm-screen').click(); // sets focus for keyboard input

const wait = 100; // milliseconds

await inputLine(page, 'ls'); // avoid timestamps
await page.waitForTimeout(wait);
await page.waitForTimeout(WAIT_MS);

await inputLine(page, 'cp months.txt other.txt');
await page.waitForTimeout(wait);
await page.waitForTimeout(WAIT_MS);

await inputLine(page, 'ls'); // avoid timestamps
await page.waitForTimeout(wait);
await page.waitForTimeout(WAIT_MS);

await inputLine(page, 'una\t'); // tab complete command name
await page.waitForTimeout(wait);
await page.waitForTimeout(WAIT_MS);

await inputLine(page, 'grep ember mon\t'); // tab complete filename
await page.waitForTimeout(wait);
await page.waitForTimeout(WAIT_MS);

await page.keyboard.press('Tab'); // list all commands
await page.waitForTimeout(wait);
await page.waitForTimeout(WAIT_MS);

await inputLine(page, 'abc'); // no such command
await page.waitForTimeout(wait);
await page.waitForTimeout(WAIT_MS);

// Hide modification times.
const modified = page.locator('span.jp-DirListing-itemModified');
Expand Down
48 changes: 48 additions & 0 deletions ui-tests/tests/utils/contents.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import type { Contents } from '@jupyterlab/services';
import type { Page } from '@playwright/test';

/**
* Helper class to interact with JupyterLite contents manager.
*
* A subset of the functionality of galata's implementation
*/
export class ContentsHelper {
constructor(readonly page: Page) {}

async directoryExists(dirPath: string): Promise<boolean> {
const content = await this._get(dirPath, false, 'directory');
return content?.type === 'directory';
}

async fileExists(filePath: string): Promise<boolean> {
const content = await this._get(filePath, false);
return content?.type === 'notebook' || content?.type === 'file';
}

async getContentMetadata(
path: string,
type: 'file' | 'directory' = 'file'
): Promise<Contents.IModel | null> {
return await this._get(path, true, type);
}

private async _get(
path: string,
wantContents: boolean,
type: 'file' | 'directory' = 'file'
): Promise<Contents.IModel | null> {
const model = await this.page.evaluate(
async ({ path, wantContents, type }) => {
const contents = window.galata.app.serviceManager.contents;
const options = { type, content: wantContents };
try {
return await contents.get(path, options);
} catch (error) {
return null;
}
},
{ path, wantContents, type }
);
return model;
}
}
16 changes: 16 additions & 0 deletions ui-tests/tests/utils/misc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Buffer } from 'node:buffer';

export const WAIT_MS = 100;
export const TERMINAL_SELECTOR = '.jp-Terminal';

export function decode64(encoded: string): string {
return Buffer.from(encoded, 'base64').toString('binary');
}

export async function inputLine(page, text: string) {
for (const char of text) {
await page.keyboard.type(char);
await page.waitForTimeout(10);
}
await page.keyboard.press('Enter');
}

0 comments on commit f943371

Please sign in to comment.