Skip to content

4 test delete a file and ensure it disappears from the file explorer #11

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

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 .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ node_modules/
# For Local Development
/.auth/
playwright.env
/test-data/
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,15 @@ This repository provides E2E integration tests for the [Theia Cloud IDE](https:/

## Setup

- Install dependencies
- Get the latest Theia IDE image from [here](ghcr.io/eclipse-theia/theia-ide/theia-ide:latest) and run it. Put the corresponding URL into the env file

- Install dependencies and playwright
```bash
npm install
```

```bash
npx playwright install
```
- To run the tests on the deployed Theia instance, run:
```bash
npx playwright test --project=deployed
Expand Down
3 changes: 1 addition & 2 deletions global.config.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
export let baseURL = 'https://theia.artemis.cit.tum.de';
export let localURL = 'https://compassionate_ride.orb.local';
export let baseURL = 'https://theia.artemis.cit.tum.de';
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"@types/node": "^22.15.3"
},
"dependencies": {
"dotenv": "^16.5.0"
"dotenv": "^16.5.0",
"fs": "^0.0.1-security"
}
}
36 changes: 31 additions & 5 deletions pages/ide/IDEPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,27 +30,35 @@ export class IDEPage {
await this.menuBar.waitForReady();
await this.editor.waitForReady();
await this.sideBar.waitForReady();
await this.page.locator('.gs-header').waitFor({ state: 'visible' });
await new Promise( resolve => setTimeout(resolve, 2000) );
}

/**
* Creates a new file with the given name
* @param fileName Name of the file to create
*/
async createNewFile(fileName: string = 'Test-1'): Promise<void> {
async createNewFile(fileName: string = 'Test-1', directory: string = 'project'): Promise<void> {
await this.menuBar.openNewFileDialog();
await this.page.getByRole('combobox', { name: 'input' }).fill(fileName);
await this.page.getByRole('option', { name: `Create New File (${fileName}),` }).locator('a').click();
await this.page.getByRole('combobox').selectOption('file:///home/' + directory);
await this.page.getByRole('button', { name: 'Create File' }).click();
}

async createNewFolder(folderName: string = 'Folder-1'): Promise<void> {
await this.menuBar.openNewFolderDialog();
await this.page.locator('.dialogBlock').getByRole('textbox', { name: 'Folder Name' }).fill(folderName);
await this.page.locator('.dialogBlock').getByRole('button', { name: 'OK' }).click();
}

/**
* Opens a file from the explorer
* @param fileName Name of the file to open
*/
async openFile(fileName: string): Promise<void> {
await this.sideBar.toggleExplorer();
await this.sideBar.openExplorer();
await this.sideBar.selectFile(fileName);
await this.sideBar.toggleExplorer();
}

/**
Expand All @@ -65,6 +73,18 @@ export class IDEPage {
await this.editor.save();
}

/**
* Deletes a file from the explorer
* @param fileName Name of the file to delete
*/
async deleteFile(fileName: string): Promise<void> {
await this.sideBar.openExplorer();
await this.sideBar.deleteFile(fileName);
await this.page.locator('.codicon-info').first().waitFor({ state: 'hidden' });
await new Promise( resolve => setTimeout(resolve, 2000) );
}


/**
* Opens the integrated terminal and executes a command
* @param command Command to execute
Expand All @@ -77,8 +97,14 @@ export class IDEPage {

// Functions that return important locators for testing

getOpenedFileLocator(fileName: string): Locator {
return this.page.getByRole('listitem', { name: `/home/project/${fileName}` });
// returns locator for file in the editor
getEditorOpenedFileLocator(fileName: string): Locator {
return this.editor.pagePart.getByRole('listitem', { name: `/home/project/${fileName}` });
}

// returns locator for file in the file explorer
getExplorerOpenedFileLocator(fileName: string): Locator {
return this.sideBar.pagePart.locator(`#explorer-view-container`).getByTitle(`/home/project/${fileName}`);
}

}
9 changes: 6 additions & 3 deletions pages/ide/components/Editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,24 @@ import { BaseComponent } from './BaseComponent';
* Handles interactions with the code editor
*/
export class Editor extends BaseComponent {

readonly pagePart = this.page.locator('#theia-main-content-panel');

async waitForReady(): Promise<void> {
// Wait for the editor area to be visible
await this.page.locator('#theia-main-content-panel').waitFor();
await this.page.locator('#theia-main-content-panel').first().waitFor();
}

async typeText(text: string): Promise<void> {
await this.page.keyboard.type(text);
}

async getCurrentText(): Promise<string> {
return await this.page.locator('.monaco-editor').textContent() || '';
return await this.pagePart.locator('.monaco-editor').textContent() || '';
}

async focusOpenedFile(fileName: string): Promise<void> {
await this.page.locator('.theia-tabBar-tab-row').getByText(fileName).click();
await this.page.locator('#theia-main-content-panel').locator('.theia-tabBar-tab-row').getByText(fileName).click();
}

async selectAll(): Promise<void> {
Expand Down
35 changes: 31 additions & 4 deletions pages/ide/components/MenuBar.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,40 @@
import { expect } from '@playwright/test';
import { BaseComponent } from './BaseComponent';

/**
* Represents the top menu bar of the IDE
* Handles interactions with File, Edit, View, etc. menus
*/
export class MenuBar extends BaseComponent {

readonly pagePart = this.page.locator('#theia-top-panel');

async waitForReady(): Promise<void> {
await this.page.locator('#theia-top-panel').waitFor();
await this.page.locator('#theia-top-panel').first().waitFor();
}

async clickFileMenu(): Promise<void> {
await this.page.locator('#theia-top-panel').getByText('File').click();
await this.pagePart.getByText('File').click();
}

async clickMenuItem(menu: string, item: string): Promise<void> {
await this.page.locator('#theia-top-panel').getByText(menu).click();
await this.page.locator('[class*="Menu-content"]').getByText(item).click();
await expect(async () => {
await this.pagePart.getByText(menu).click();
await expect(this.page.locator('[class*="MenuBar-menu"]')).toBeVisible();
}).toPass();
await this.page.locator('[class*="MenuBar-menu"]').getByText(item).click();
}

async clickMenuItemNth(menu: string, item: string, nth: number): Promise<void> {
await expect(async () => {
await this.pagePart.getByText(menu).click();
await expect(this.page.locator('[class*="MenuBar-menu"]')).toBeVisible();
}).toPass();
await this.page.locator('[class*="MenuBar-menu"]').getByText(item).nth(nth).click();
}

async saveFile(): Promise<void> {
await this.clickMenuItemNth('File', 'Save', 1);
}

async openNewFileDialog(): Promise<void> {
Expand All @@ -29,4 +48,12 @@ export class MenuBar extends BaseComponent {
async openTerminal(): Promise<void> {
await this.clickMenuItem('Terminal', 'New Terminal');
}

async pressUndo(): Promise<void> {
await this.clickMenuItem('Edit', 'Undo');
}

async pressRedo(): Promise<void> {
await this.clickMenuItem('Edit', 'Redo');
}
}
60 changes: 55 additions & 5 deletions pages/ide/components/SideBar.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,78 @@
import { expect } from '@playwright/test';
import { BaseComponent } from './BaseComponent';

/**
* Represents the side bar of the IDE
* Handles interactions with file explorer, search, git, etc.
*/
export class SideBar extends BaseComponent {

readonly pagePart = this.page.locator('#theia-left-content-panel');

async waitForReady(): Promise<void> {
await this.page.locator('#theia-left-content-panel div').waitFor();
await this.page.locator('#theia-left-content-panel').first().waitFor();
}

// Start of Explorer Section

async toggleExplorer(): Promise<void> {
await this.page.locator('#shell-tab-explorer-view-container').click();
await this.pagePart.locator('#shell-tab-explorer-view-container').click();
}

async openExplorer(): Promise<void> {
if (await this.pagePart.locator('.theia-sidepanel-title').getByText('EXPLORER').isHidden()) {
await this.pagePart.locator('#shell-tab-explorer-view-container').click();
}
}

async closeExplorer(): Promise<void> {
if (await this.pagePart.locator('.theia-sidepanel-title').getByText('EXPLORER').isVisible()) {
await this.pagePart.locator('#shell-tab-explorer-view-container').click();
}
}

/**
* Opens all folders in the given path in the explorer
* @param folderPath Path of the folder to open in type '/folder1/folder2/folder3/file'
*/
async openFolderPath(folderPath: string): Promise<void> {
const segments = folderPath.split("/").filter(Boolean);
for (const segment of segments) {
if (await this.page.locator('#theia-left-side-panel').getByTitle(segment).last().locator(`.theia-mod-collapsed`).isVisible()) {
await this.page.locator('#theia-left-side-panel').getByTitle(segment).last().locator(`.theia-mod-collapsed`).click();
}
}
}

// End of Explorer Section

// Start of Search Section

async openSearch(): Promise<void> {
await this.page.locator('#shell-tab-search-view-container').click();
await this.pagePart.locator('#shell-tab-search-view-container').click();
}

// End of Search Section

// Start of Git Section

async openGit(): Promise<void> {
await this.page.locator('#shell-tab-scm-view-container').click();
await this.pagePart.locator('#shell-tab-scm-view-container').click();
}

// End of Git Section

async selectFile(fileName: string): Promise<void> {
await this.page.locator('#theia-left-side-panel').getByTitle(`/home/project/${fileName}`).click();
await this.pagePart.locator('#theia-left-side-panel').getByTitle(`/home/project/${fileName}`).dblclick();
}

async deleteFile(fileName: string): Promise<void> {
await expect(async () => {
await this.pagePart.locator('#theia-left-side-panel').getByTitle(`/home/project/${fileName}`).click({ button: "right" });
await expect(this.page.locator('[class*="Menu-content"]')).toBeVisible();
}).toPass();
await this.page.locator('[class*="Menu-content"]').locator('[class*="Menu-itemLabel"]').getByText('Delete').click();
await this.page.locator('.dialogBlock').getByText('OK').click();
}

}
14 changes: 10 additions & 4 deletions pages/ide/components/Terminal.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Locator } from '@playwright/test';
import { expect, Locator } from '@playwright/test';
import { BaseComponent } from './BaseComponent';

/**
Expand All @@ -14,10 +14,12 @@ export class Terminal extends BaseComponent {
await this.page.getByRole('listitem', { name: 'Terminal' }).waitFor();
}


async open(): Promise<void> {
await this.page.locator('#theia-top-panel').getByText('Terminal').click();
await this.page.locator('[class*="Menu-content"]').getByText('New Terminal').nth(0).click();
await expect(async () => {
await this.page.locator('#theia-top-panel').getByText('Terminal').click();
await expect(this.page.locator('[class*="MenuBar-menu"]')).toBeVisible();
}).toPass();
await this.page.locator('[class*="MenuBar-menu"]').getByText('New Terminal').nth(0).click();
await this.waitForReady();
}

Expand All @@ -40,4 +42,8 @@ export class Terminal extends BaseComponent {
async close(): Promise<void> {
await this.executeCommand('exit');
}

async focusTerminal(): Promise<void> {
await this.terminalLocator.getByRole('listitem', { name: 'Terminal' }).first().click();
}
}
30 changes: 28 additions & 2 deletions pages/landing/LandingPage.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,30 @@
import { Page } from '@playwright/test';
import { Locator, Page } from '@playwright/test';

/**
* A class which encapsulates the landing page of Theia with UI selectors.
*/
export class LandingPage {
private readonly page: Page;
readonly page: Page;

readonly languageCLocator: Locator;
readonly languageJavaLocator: Locator;
readonly languageJSLocator: Locator;
readonly languageOcamlLocator: Locator;
readonly languagePythonLocator: Locator;
readonly languageRustLocator: Locator;

constructor(page: Page) {
this.page = page;
this.languageCLocator = this.page.getByRole('button', { name: 'Launch C' });
this.languageJavaLocator = this.page.getByRole('button', { name: 'Launch Java', exact: true });
this.languageJSLocator = this.page.getByRole('button', { name: 'Launch Javascript' });
this.languageOcamlLocator = this.page.getByRole('button', { name: 'Launch Ocaml' });
this.languagePythonLocator = this.page.getByRole('button', { name: 'Launch Python' });
this.languageRustLocator = this.page.getByRole('button', { name: 'Launch Rust' });
}

async waitForReady() {
await this.page.locator('img').waitFor();
}

async clickLoginButton() {
Expand All @@ -21,8 +38,17 @@ export class LandingPage {
await this.page.getByRole('button', { name: 'Sign in' }).click();
}

async logout() {
await this.page.getByRole('link', { name: 'logout' }).click();
}

async launchLanguage(language: string) {
const languageButton = await this.page.getByRole('button', { name: `Launch ${language}` });
await languageButton.click();
}

retrieveAllLanguageLocators() {
return [this.languageCLocator, this.languageJavaLocator, this.languageJSLocator, this.languageOcamlLocator, this.languagePythonLocator, this.languageRustLocator];
}

}
Loading