Skip to content

Commit

Permalink
Merge pull request #1341 from kubeshop/andreiv1992/feat/work-with-git…
Browse files Browse the repository at this point in the history
…-folder

Andreiv1992/feat/work with git folder
  • Loading branch information
andreivinaga authored Feb 14, 2022
2 parents d717686 + f8df4ff commit 247f007
Show file tree
Hide file tree
Showing 17 changed files with 261 additions and 29 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/monokle-ui-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: monokle-ui-tests
on:
push:
branches:
- andreiv1992/test/more-tests-around-projects
- andreiv1992/feat/work-with-git-folder

workflow_dispatch:

Expand Down
5 changes: 3 additions & 2 deletions docs/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,6 @@ await electronApp.evaluate(({ ipcMain }, params) => {
```

Examples:
- [override in electron](src/components/atoms/FileExplorer/FileExplorer.tsx)
- [override in tests](tests/models/projectsDropdown.ts)

- [override in electron](https://github.com/kubeshop/monokle/blob/main/src/components/atoms/FileExplorer/FileExplorer.tsx)
- [override in tests](https://github.com/kubeshop/monokle/blob/main/tests/models/projectsDropdown.ts)
3 changes: 2 additions & 1 deletion playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ import {PlaywrightTestConfig} from '@playwright/test';

const config: PlaywrightTestConfig = {
testDir: './tests',
timeout: 80000,
timeout: 200000,
expect: {
toMatchSnapshot: {threshold: 0.2},
},
retries: 3
};

export default config;
2 changes: 2 additions & 0 deletions src/components/organisms/PaneManager/PaneManager.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ const PaneManager = () => {
placement="right"
>
<MenuButton
id="kustomize-pane"
isSelected={Boolean(activeProject) && leftMenuSelection === 'kustomize-pane'}
isActive={Boolean(activeProject) && leftActive}
onClick={() => setLeftActiveMenu('kustomize-pane')}
Expand All @@ -245,6 +246,7 @@ const PaneManager = () => {
placement="right"
>
<MenuButton
id="helm-pane"
isSelected={Boolean(activeProject) && leftMenuSelection === 'helm-pane'}
isActive={Boolean(activeProject) && leftActive}
onClick={() => setLeftActiveMenu('helm-pane')}
Expand Down
8 changes: 5 additions & 3 deletions src/components/organisms/UpdateModal/UpdateModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,11 @@ const UpdateModal = () => {
)
}
>
{newVersion.code === NewVersionCode.Errored ? getErrorMessage(newVersion.data?.errorCode) : null}
{newVersion.code === NewVersionCode.NotAvailable ? <div>New version is not available!</div> : null}
{newVersion.code === NewVersionCode.Downloaded ? <div>New version is downloaded!</div> : null}
<span id="UpdateModal">
{newVersion.code === NewVersionCode.Errored ? getErrorMessage(newVersion.data?.errorCode) : null}
{newVersion.code === NewVersionCode.NotAvailable ? <div>New version is not available!</div> : null}
{newVersion.code === NewVersionCode.Downloaded ? <div>New version is downloaded!</div> : null}
</span>
</StyledModal>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ const KustomizePatchSectionBlueprint: SectionBlueprint<K8sResource, KustomizePat
},
getGroups: scope => {
const patchResources = Object.values(scope.resourceMap).filter(resource => resource.name.startsWith('Patch:'));
const patcheResourcesByKind: Record<string, K8sResource[]> = patchResources.reduce<Record<string, K8sResource[]>>(
const patchResourcesByKind: Record<string, K8sResource[]> = patchResources.reduce<Record<string, K8sResource[]>>(
(acc, resource) => {
if (acc[resource.kind]) {
acc[resource.kind].push(resource);
Expand All @@ -56,7 +56,7 @@ const KustomizePatchSectionBlueprint: SectionBlueprint<K8sResource, KustomizePat
},
{}
);
return Object.entries(patcheResourcesByKind)
return Object.entries(patchResourcesByKind)
.map(([resourceKind, resources]) => {
return {
id: resourceKind,
Expand Down
23 changes: 14 additions & 9 deletions tests/base.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import {Page} from 'playwright';
import {expect, test} from '@playwright/test';
import {
findDrawer,
waitForDrawerToHide,
waitForDrawerToShow,
} from './antdHelpers';
import {clickOnMonokleLogo, ElectronAppInfo, startApp} from './electronHelpers';
import {pause} from './utils';
import {getRecordingPath, pause} from './utils';

let appWindow: Page = {} as any;
let appInfo: ElectronAppInfo = {} as any;
Expand Down Expand Up @@ -58,32 +59,36 @@ test('Validate ClusterContainer', async () => {
});

test('Validate settings drawer', async () => {
const settingsTitle = appWindow.locator('.ant-drawer-open .ant-drawer-title');
expect(await settingsTitle.isVisible()).toBe(false);
await appWindow.screenshot({path: getRecordingPath(appInfo.platform, 'before-settings-drawer.png')});
let drawer = await findDrawer(appWindow, 'Settings');
expect(drawer).toBeFalsy();

await appWindow.click("span[aria-label='setting']", {noWaitAfter: true, force: true});
await pause(20000);
expect(await settingsTitle.isVisible()).toBe(true);
await appWindow.screenshot({path: getRecordingPath(appInfo.platform, 'settings-drawer.png')});
drawer = await waitForDrawerToShow(appWindow, 'Settings', 40000);

expect(drawer).toBeTruthy();

await clickOnMonokleLogo(appWindow);
await pause(20000);
expect(await settingsTitle.isVisible()).toBe(false);

expect(await waitForDrawerToHide(appWindow, 'Settings')).toBeTruthy();
});

test('Validate notifications drawer', async () => {
appWindow.click("//span[@aria-label='bell' and contains(@class,'anticon')]", {
await appWindow.click("//span[@aria-label='bell' and contains(@class,'anticon')]", {
noWaitAfter: true,
force: true,
});

await appWindow.screenshot({path: getRecordingPath(appInfo.platform, 'notifications-drawer.png')});
expect(await waitForDrawerToShow(appWindow, 'Notifications', 5000)).toBeTruthy();
await clickOnMonokleLogo(appWindow);

expect(await waitForDrawerToHide(appWindow, 'Notifications')).toBeTruthy();
});

test.afterAll(async () => {
await appWindow.screenshot({path: `test-output/${appInfo.platform}/screenshots/final-screen.png`});
await appWindow.screenshot({path: getRecordingPath(appInfo.platform, 'final-screen.png')});
await appWindow.context().close();
await appWindow.close();
});
19 changes: 15 additions & 4 deletions tests/electronHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ interface StartAppResponse {
appInfo: ElectronAppInfo;
}

const modalsToWait = ['UpdateModal', 'WelcomeModal'];

/**
* Find the latest build and start monokle app for testing
*/
Expand Down Expand Up @@ -51,10 +53,19 @@ export async function startApp(): Promise<StartAppResponse> {
const appWindow: Page = windows[0];
appWindow.on('console', console.log);

if (await waitForModalToShow(appWindow, 'WelcomeModal', 20000)) {
await clickOnMonokleLogo(appWindow);
await pause(500);
await waitForModalToHide(appWindow, 'WelcomeModal');
await appWindow.screenshot({
path: getRecordingPath(appInfo.platform, 'before-modals.png')
});

for (const modalName of modalsToWait) {
if (await waitForModalToShow(appWindow, modalName, 20000)) {
await clickOnMonokleLogo(appWindow);
await pause(500);
await waitForModalToHide(appWindow, modalName);
}
await appWindow.screenshot({
path: getRecordingPath(appInfo.platform, `modal-gone-${modalName}.png`)
});
}

// Capture a screenshot.
Expand Down
124 changes: 124 additions & 0 deletions tests/git.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import {expect, test} from '@playwright/test';
import {Page} from 'playwright';
import {ElectronApplication} from 'playwright-core';
import {execSync} from 'child_process';
import * as path from 'path';
import * as fs from 'fs';
import {ElectronAppInfo, startApp} from './electronHelpers';
import {pause} from './utils';
import {MainWindow} from './models/mainWindow';
import {FileExplorerPane} from './models/fileExplorerPane';
import {KustomizePane} from './models/kustomizePane';
import {HelmPane} from './models/helmPane';
import {StartProjectPane} from './models/startProjectPane';
import {NavigatorPane} from './models/navigatorPane';

let appWindow: Page;
let appInfo: ElectronAppInfo;
let electronApp: ElectronApplication;

const clonePath = path.join(__dirname, '..', '..');
const projectPath = path.join(clonePath, 'manifest-test-data');
const repo = 'https://github.com/kubeshop/manifest-test-data';

let mainWindow: MainWindow;
let fileExplorerPane: FileExplorerPane;
let kustomizePane: KustomizePane;
let helmPane: HelmPane;
let startProjectPane: StartProjectPane;
let navigatorPane: NavigatorPane;

test.beforeAll(async () => {
const startAppResponse = await startApp();
appWindow = startAppResponse.appWindow;
appInfo = startAppResponse.appInfo;
electronApp = startAppResponse.electronApp;

mainWindow = new MainWindow(appWindow);
fileExplorerPane = new FileExplorerPane(appWindow);
kustomizePane = new KustomizePane(appWindow);
helmPane = new HelmPane(appWindow);
startProjectPane = new StartProjectPane(appWindow);
navigatorPane = new NavigatorPane(appWindow);

appWindow.on('console', console.log);

execSync(`git clone ${repo}`, {
cwd: `${clonePath}`,
});
});

const startCommit = 'aeb1e59a03913b00020eca6ac2a416d085f34a6b';
const removeSomeFiles = 'f5518240cf7cac1f686c1bc9e4ca8099bfd7daa1';
const removeMoreFiles = '28879f29f62c8357b5ca988e475db30e13c8300b';

async function goToCommit(hash: string) {
execSync(`git checkout ${hash}`, {
cwd: `${projectPath}`,
});

await pause(5000);
}

const testData = [
{
hash: startCommit,
fileExplorerCount: 53,
kustomizeCount: 22,
helmCount: 4,
navigatorCount: 55,
},
{
hash: removeSomeFiles,
fileExplorerCount: 32,
kustomizeCount: 5,
helmCount: 4,
navigatorCount: 48,
},
{
hash: removeMoreFiles,
fileExplorerCount: 15,
kustomizeCount: 2,
helmCount: 4,
navigatorCount: 35,
},
{
hash: startCommit,
fileExplorerCount: 53,
kustomizeCount: 22,
helmCount: 4,
navigatorCount: 55,
},
];

test('all files should be loaded', async () => {
await startProjectPane.createProjectFromFolder(electronApp, projectPath);
await pause(10000);

// eslint-disable-next-line no-restricted-syntax
for (const data of testData) {
console.log(`testing commit hash: ${data.hash}`);
await goToCommit(data.hash);

expect(parseInt(await navigatorPane.resourcesCount.textContent(), 10)).toEqual(data.navigatorCount);

await mainWindow.clickFileExplorer();
expect((await fileExplorerPane.projectName.textContent())?.includes(projectPath)).toBe(true);
expect(await fileExplorerPane.fileCount.textContent()).toEqual(`${data.fileExplorerCount} files`);

await mainWindow.clickKustomizeButton();
const kustomizeInnerTexts = (await kustomizePane.kustomizeItemsContainer.allInnerTexts())[0].split('\n');
expect(kustomizeInnerTexts.length).toEqual(data.kustomizeCount);

await mainWindow.clickHelmButton();
const helmInnerTexts = (await helmPane.helmItemsContainer.allInnerTexts())[0].split('\n');
expect(helmInnerTexts.length).toEqual(data.helmCount);
}
});

test.afterAll(async () => {
fs.rmSync(projectPath, { recursive: true, force: true });
await appWindow.screenshot({path: `test-output/${appInfo.platform}/screenshots/final-screen.png`});
await appWindow.context().close();
await appWindow.close();
});
19 changes: 19 additions & 0 deletions tests/models/helmPane.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import {Locator, Page} from 'playwright';

export class HelmPane {

private _page: Page;

private readonly _helmItemsContainer: Locator;

constructor(page: Page) {
this._page = page;

this._helmItemsContainer = page.locator('#helm-sections-container');
}

get helmItemsContainer() {
return this._helmItemsContainer;
}

}
19 changes: 19 additions & 0 deletions tests/models/kustomizePane.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import {Locator, Page} from 'playwright';

export class KustomizePane {

private _page: Page;

private readonly _kustomizeItemsContainer: Locator;

constructor(page: Page) {
this._page = page;

this._kustomizeItemsContainer = page.locator('#kustomize-sections-container');
}

get kustomizeItemsContainer() {
return this._kustomizeItemsContainer;
}

}
12 changes: 12 additions & 0 deletions tests/models/mainWindow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ export class MainWindow {
private readonly _projectsDropdown: Locator;
private readonly _backToProject: Locator;
private readonly _fileExplorerButton: Locator;
private readonly _kustomizeButton: Locator;
private readonly _helmButton: Locator;

constructor(page: Page) {
this._page = page;
Expand All @@ -17,6 +19,8 @@ export class MainWindow {
this._backToProject = page.locator('#projects-dropdown-container > button:last-child');

this._fileExplorerButton = page.locator('#file-explorer');
this._kustomizeButton = page.locator('#kustomize-pane');
this._helmButton = page.locator('#helm-pane');
}

async clickLogo() {
Expand All @@ -35,4 +39,12 @@ export class MainWindow {
await this._fileExplorerButton.click();
}

async clickKustomizeButton() {
await this._kustomizeButton.click();
}

async clickHelmButton() {
await this._helmButton.click();
}

}
8 changes: 8 additions & 0 deletions tests/models/navigatorPane.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,23 @@ export class NavigatorPane {
private _page: Page;

private readonly _createResourceButton: Locator;
private readonly _sectionsContainer: Locator;
private readonly _resourcesCount: Locator;

constructor(page: Page) {
this._page = page;

this._createResourceButton = page.locator('#create-resource-button');
this._sectionsContainer = page.locator('#navigator-sections-container');
this._resourcesCount = page.locator('#navigator-sections-container li:first-child span > span:nth-child(2)');
}

async clickOnNewResource() {
await this._createResourceButton.click();
}

get resourcesCount() {
return this._resourcesCount;
}

}
Loading

0 comments on commit 247f007

Please sign in to comment.