Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: add opened editor e2e test #1863

Merged
merged 14 commits into from
Oct 31, 2022
Merged
24 changes: 24 additions & 0 deletions tools/playwright/src/editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,4 +103,28 @@ export class OpenSumiEditor extends OpenSumiView {
await this.app.page.waitForTimeout(200);
}
}

async triggerTitleMenu(name: string) {
const tab = await this.getTabElement();
const actions = (await tab?.$$('[class*="iconAction___"]')) || [];
for (const action of actions) {
const title = await action.getAttribute('title');
if (title === name) {
await action.click();
break;
}
}
}

async triggerTitleMenuById(id: string) {
const tab = await this.getTabElement();
const actions = (await tab?.$$('[class*="iconAction___"]')) || [];
for (const action of actions) {
const title = await action.getAttribute('id');
if (title === id) {
await action.click();
break;
}
}
}
}
60 changes: 59 additions & 1 deletion tools/playwright/src/explorer-view.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { OpenSumiApp } from './app';
import { OpenSumiFileTreeView } from './filetree-view';
import { OpenSumiOpenedEditorView } from './opened-editor-view';
import { OpenSumiPanel } from './panel';
import { OpenSumiTreeNode } from './tree-node';

Expand All @@ -9,7 +10,10 @@ export class OpenSumiExplorerFileStatNode extends OpenSumiTreeNode {
}

async isFolder() {
const icon = await this.elementHandle.waitForSelector("[class*='file_icon___']");
const icon = await this.elementHandle.$("[class*='file_icon___']");
if (!icon) {
return false;
}
const className = await icon.getAttribute('class');
return className?.includes('folder-icon');
}
Expand All @@ -27,13 +31,45 @@ export class OpenSumiExplorerFileStatNode extends OpenSumiTreeNode {
await this.elementHandle.click();
}
}

async isDirty() {
const classname = await this.elementHandle.getAttribute('class');
if (classname?.includes('mod_dirty__')) {
return true;
}
return false;
}
}

export class OpenSumiExplorerOpenedEditorNode extends OpenSumiTreeNode {
async getRelativePath() {
return await (await this.elementHandle.$('[class*="opened_editor_node_description__"]'))?.textContent();
}

async isGroup() {
const icon = await this.elementHandle.waitForSelector("[class*='file_icon___']");
const className = await icon.getAttribute('class');
return className?.includes('folder-icon');
}

async getMenuItemByName(name: string) {
const contextMenu = await this.openContextMenu();
const menuItem = await contextMenu.menuItemByName(name);
return menuItem;
}

async open() {
await this.elementHandle.click();
}
}

export class OpenSumiExplorerView extends OpenSumiPanel {
private _fileTreeView: OpenSumiFileTreeView;
private _openedEditorView: OpenSumiOpenedEditorView;

constructor(app: OpenSumiApp) {
super(app, 'explorer');
this._openedEditorView = new OpenSumiOpenedEditorView(this.app, 'OPENED EDITORS');
}

initFileTreeView(name: string) {
Expand All @@ -44,6 +80,10 @@ export class OpenSumiExplorerView extends OpenSumiPanel {
return this._fileTreeView;
}

get openedEditorView() {
return this._openedEditorView;
}

async getFileStatTreeNodeByPath(path: string) {
const treeItems = await (await this.fileTreeView.getViewElement())?.$$('[class*="file_tree_node__"]');
if (!treeItems) {
Expand All @@ -61,4 +101,22 @@ export class OpenSumiExplorerView extends OpenSumiPanel {
return new OpenSumiExplorerFileStatNode(node, this.app);
}
}

async getOpenedEditorTreeNodeByPath(path: string) {
const treeItems = await (await this.openedEditorView.getViewElement())?.$$('[class*="opened_editor_node__"]');
if (!treeItems) {
return;
}
let node;
for (const item of treeItems) {
const title = await item.getAttribute('title');
if (title?.includes(path)) {
node = item;
break;
}
}
if (node) {
return new OpenSumiExplorerFileStatNode(node, this.app);
}
}
}
18 changes: 18 additions & 0 deletions tools/playwright/src/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,19 @@
export * from './app';
export * from './component-editor';
export * from './context-menu';
export * from './editor';
export * from './explorer-view';
export * from './filetree-view';
export * from './menu-item';
export * from './menu';
export * from './menubar';
export * from './opened-editor-view';
export * from './panel';
export * from './quick-command-palette';
export * from './search-view';
export * from './terminal';
export * from './text-editor';
export * from './tree-node';
export * from './view-base';
export * from './view';
export * from './workspace';
28 changes: 28 additions & 0 deletions tools/playwright/src/opened-editor-view.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { OpenSumiApp } from './app';
import { OpenSumiView } from './view';

export class OpenSumiOpenedEditorView extends OpenSumiView {
constructor(app: OpenSumiApp, workspaceName: string) {
super(app, {
viewSelector: '#file-opened-editor',
tabSelector: '#file-opened-editor [tabindex="0"]',
name: workspaceName,
});
}

async getTitleActionByName(name: string) {
const header = await this.getTabElement();
if (!header) {
return;
}
await header.hover();
const titleAction = await header.waitForSelector('[class*="titleActions___"]');
const actions = await titleAction.$$('[class*="iconAction__"]');
for (const action of actions) {
const title = await action.getAttribute('title');
if (name === title) {
return action;
}
}
}
}
55 changes: 54 additions & 1 deletion tools/playwright/src/tests/explorer-view.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,17 @@ import { isWindows } from '@opensumi/ide-utils';
import { OpenSumiApp } from '../app';
import { OpenSumiExplorerView } from '../explorer-view';
import { OpenSumiFileTreeView } from '../filetree-view';
import { OpenSumiOpenedEditorView } from '../opened-editor-view';
import { OpenSumiTerminal } from '../terminal';
import { OpenSumiTextEditor } from '../text-editor';
import { OpenSumiWorkspace } from '../workspace';

import test, { page } from './hooks';

let app: OpenSumiApp;
let explorer: OpenSumiExplorerView;
let fileTreeView: OpenSumiFileTreeView;
let openedEditorView: OpenSumiOpenedEditorView;
let workspace: OpenSumiWorkspace;

test.describe('OpenSumi Explorer Panel', () => {
Expand All @@ -24,6 +27,7 @@ test.describe('OpenSumi Explorer Panel', () => {
explorer = await app.open(OpenSumiExplorerView);
explorer.initFileTreeView(workspace.workspace.displayName);
fileTreeView = explorer.fileTreeView;
openedEditorView = explorer.openedEditorView;
});

test.afterAll(() => {
Expand Down Expand Up @@ -93,6 +97,10 @@ test.describe('OpenSumi Explorer Panel', () => {
await input.type(newFileName, { delay: 200 });
await app.page.keyboard.press('Enter');
}
await app.page.waitForTimeout(200);
const newFile = await explorer.getFileStatTreeNodeByPath(`${newFileName}`);
expect(newFile).toBeDefined();
expect(await newFile?.isFolder()).toBeFalsy();
});

test('can new folder from toolbar', async () => {
Expand Down Expand Up @@ -143,7 +151,52 @@ test.describe('OpenSumi Explorer Panel', () => {
await app.page.waitForTimeout(200);
const file_1 = await explorer.getFileStatTreeNodeByPath(`${filterString}.js`);
expect(file_1).toBeDefined();
const file_2 = await explorer.getFileStatTreeNodeByPath('editor.js');
let file_2 = await explorer.getFileStatTreeNodeByPath('editor.js');
expect(file_2).toBeUndefined();
await app.page.keyboard.press('Escape');
file_2 = await explorer.getFileStatTreeNodeByPath('editor.js');
expect(file_2).toBeDefined();
});

test('should show opened files on the opened editor panel', async () => {
await openedEditorView.open();
expect(await openedEditorView.isVisible()).toBeTruthy();
const testFilePath = 'editor.js';
await app.openEditor(OpenSumiTextEditor, explorer, testFilePath);
await app.page.waitForTimeout(500);
const node = await explorer.getOpenedEditorTreeNodeByPath(testFilePath);
expect(node).toBeDefined();
});

test('should show dirty icon on the opened editor panel', async () => {
await openedEditorView.open();
expect(await openedEditorView.isVisible()).toBeTruthy();
const testFilePath = 'editor3.js';
const editor = await app.openEditor(OpenSumiTextEditor, explorer, testFilePath);
await editor.addTextToNewLineAfterLineByLineNumber(
1,
`const a = 'a';
console.log(a);`,
);
await app.page.waitForTimeout(1000);
let node = await explorer.getOpenedEditorTreeNodeByPath(testFilePath);
expect(await node?.isDirty()).toBeTruthy();
await editor.save();
await app.page.waitForTimeout(1000);
node = await explorer.getOpenedEditorTreeNodeByPath(testFilePath);
expect(await node?.isDirty()).toBeFalsy();
});

test('split file on the editor should showing on two group', async () => {
await openedEditorView.open();
expect(await openedEditorView.isVisible()).toBeTruthy();
const testFilePath = 'editor3.js';
const editor = await app.openEditor(OpenSumiTextEditor, explorer, testFilePath);
await editor.triggerTitleMenuById('editor.splitToRight');
await app.page.waitForTimeout(2000);
const group1 = await explorer.getOpenedEditorTreeNodeByPath('Group 1');
const group2 = await explorer.getOpenedEditorTreeNodeByPath('Group 2');
expect(group1).toBeDefined();
expect(group2).toBeDefined();
});
});
1 change: 0 additions & 1 deletion tools/playwright/src/text-editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,6 @@ export class OpenSumiTextEditor extends OpenSumiEditor {
}
return undefined;
}

async lineByLineNumber(lineNumber: number): Promise<ElementHandle<SVGElement | HTMLElement> | undefined> {
await this.activate();
const viewElement = await this.getViewElement();
Expand Down