-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
[ TS-SELENIUM ] Investigating new typescript related test framework #13200
Changes from 46 commits
d706904
e4afc5b
3cb248e
ca8b301
e307ce4
8c2f2f5
13b64e3
269617f
79b5a09
aa98cff
bd596ca
15853ec
2dbc438
10f011f
e9fa3ff
6f24843
cc8beca
124e0cb
cbffa2f
6830399
3473987
292d32e
103fb74
508831e
6c9fdcf
3297b1f
0e414fc
edeff86
f52e833
2de6d1f
acfd277
fd8573c
571ee36
61d58bd
1d2673e
5aab39a
8bacf5e
5902195
37e4726
150145c
db6ba5f
be1d841
29d9856
fbcd9af
65d45e6
2042f73
dcf5a00
a9cd9e8
8a78567
d261298
3a4ae9e
48d5d0f
fa58f3c
b77621f
19e0434
708dde9
b4ce619
1302bdc
659d2e5
3e0223c
b25c53f
b3128c1
f4e5ca5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
## Requirements | ||
- node 8.x | ||
- "Chrome" browser 69.x or later | ||
|
||
## Default launch | ||
- npm install && npm test | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Dashboard uses |
||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These two commands are not enough. I miss information about how to run the app (maybe link to a different readme would be enough). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is not the responsibility of this module to deploy Che. It just goes to the provided link and performs tests. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I completely agree with you. This is the reason why I suggested to just provide the link to the instructions. |
||
## Custom launch | ||
**Use environment variables (check default values in 'TestConstants.ts' file):** | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I suggest to only mentions the file |
||
### application url | ||
- TS_SELENIUM_BASE_URL *( string )* | ||
|
||
### headless launch | ||
- TS_SELENIUM_HEADLESS *( boolean )* | ||
|
||
### timeouts | ||
- TS_SELENIUM_DEFAULT_ATTEMPTS *( number )* | ||
- TS_SELENIUM_DEFAULT_POLLING *( number )* | ||
- TS_SELENIUM_DEFAULT_TIMEOUT *( number )* | ||
- TS_SELENIUM_LANGUAGE_SERVER_START_TIMEOUT *( number )* | ||
- TS_SELENIUM_LOAD_PAGE_TIMEOUT *( number )* | ||
- TS_SELENIUM_START_WORKSPACE_TIMEOUT *( number )* | ||
- TS_SELENIUM_WORKSPACE_STATUS_ATTEMPTS *( number )* | ||
- TS_SELENIUM_WORKSPACE_STATUS_POLLING *( number )* |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
/********************************************************************* | ||
* Copyright (c) 2019 Red Hat, Inc. | ||
* | ||
* This program and the accompanying materials are made | ||
* available under the terms of the Eclipse Public License 2.0 | ||
* which is available at https://www.eclipse.org/legal/epl-2.0/ | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 | ||
**********************************************************************/ | ||
|
||
function readEnvAndSetValue(envProperty: any, defaultValue: string | number | boolean): any { | ||
const propertyValue = envProperty | ||
if (!propertyValue) { | ||
return defaultValue; | ||
} | ||
|
||
return propertyValue | ||
} | ||
|
||
export const TestConstants = { | ||
TS_SELENIUM_HEADLESS: readEnvAndSetValue(process.env.TS_SELENIUM_HEADLESS, false), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This code is unnecessarily complicated. You can replace it with something like this for boolean values TS_SELENIUM_HEADLESS: process.env.TS_SELENIUM_HEADLESS === 'true', this for numbers TS_SELENIUM_DEFAULT_ATTEMPTS: Number(process.env.TS_SELENIUM_DEFAULT_ATTEMPTS) || 5, or this for strings TS_SELENIUM_BASE_URL: process.env.TS_SELENIUM_BASE_URL || "http://che-che.192.168.99.100.nip.io" There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice catch! Thank you. |
||
|
||
TS_SELENIUM_START_WORKSPACE_TIMEOUT: readEnvAndSetValue(process.env.TS_SELENIUM_START_WORKSPACE_TIMEOUT, 240000), | ||
TS_SELENIUM_LOAD_PAGE_TIMEOUT: readEnvAndSetValue(process.env.TS_SELENIUM_LOAD_PAGE_TIMEOUT, 120000), | ||
TS_SELENIUM_LANGUAGE_SERVER_START_TIMEOUT: readEnvAndSetValue(process.env.TS_SELENIUM_LANGUAGE_SERVER_START_TIMEOUT, 180000), | ||
|
||
TS_SELENIUM_DEFAULT_TIMEOUT: readEnvAndSetValue(process.env.TS_SELENIUM_DEFAULT_TIMEOUT, 20000), | ||
TS_SELENIUM_DEFAULT_ATTEMPTS: readEnvAndSetValue(process.env.TS_SELENIUM_DEFAULT_ATTEMPTS, 5), | ||
TS_SELENIUM_DEFAULT_POLLING: readEnvAndSetValue(process.env.TS_SELENIUM_DEFAULT_POLLING, 1000), | ||
|
||
TS_SELENIUM_WORKSPACE_STATUS_ATTEMPTS: readEnvAndSetValue(process.env.TS_SELENIUM_WORKSPACE_STATUS_ATTEMPTS, 90), | ||
TS_SELENIUM_WORKSPACE_STATUS_POLLING: readEnvAndSetValue(process.env.TS_SELENIUM_WORKSPACE_STATUS_POLLING, 10000), | ||
|
||
TS_SELENIUM_BASE_URL: readEnvAndSetValue(process.env.TS_SELENIUM_BASE_URL, "http://che-che.192.168.99.100.nip.io"), | ||
|
||
TS_SELENIUM_RESOLUTION_WIDTH: readEnvAndSetValue(process.env.TS_SELENIUM_BASE_URL, 1920), | ||
TS_SELENIUM_RESOLUTION_HEIGHT: readEnvAndSetValue(process.env.TS_SELENIUM_BASE_URL, 1080) | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it is default value which valid for minikube Che. For customization may be used the "TS_SELENIUM_BASE_URL" environment variable There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i am not sure it that 192.168.99.100 default minikube value and nip.io suffix also can be changed it may be has many values for customizing. It may be a bit confuse our contributors. I guess something like localhost will be more clearer There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are a lot of variants, I just put one of them There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Couldn't we make that parameter as "mandatory", as we can agree there is not right "default" value? |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
/********************************************************************* | ||
* Copyright (c) 2019 Red Hat, Inc. | ||
* | ||
* This program and the accompanying materials are made | ||
* available under the terms of the Eclipse Public License 2.0 | ||
* which is available at https://www.eclipse.org/legal/epl-2.0/ | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 | ||
**********************************************************************/ | ||
import * as mocha from 'mocha'; | ||
import { Driver } from './Driver'; | ||
import { e2eContainer } from '../inversify.config'; | ||
import { TYPES } from '../inversify.types'; | ||
import * as fs from 'fs'; | ||
import { TestConstants } from '../TestConstants'; | ||
|
||
const driver: Driver = e2eContainer.get(TYPES.Driver); | ||
|
||
class CheReporter extends mocha.reporters.Spec { | ||
|
||
constructor(runner: mocha.Runner, options: mocha.MochaOptions) { | ||
super(runner, options); | ||
|
||
runner.on('start', async (test: mocha.Test) => { | ||
const launchInformation: string = | ||
`################## Launch Information ################## | ||
|
||
TS_SELENIUM_BASE_URL: ${TestConstants.TS_SELENIUM_BASE_URL} | ||
TS_SELENIUM_HEADLESS: ${TestConstants.TS_SELENIUM_HEADLESS} | ||
|
||
TS_SELENIUM_DEFAULT_ATTEMPTS: ${TestConstants.TS_SELENIUM_DEFAULT_ATTEMPTS} | ||
TS_SELENIUM_DEFAULT_POLLING: ${TestConstants.TS_SELENIUM_DEFAULT_POLLING} | ||
TS_SELENIUM_DEFAULT_TIMEOUT: ${TestConstants.TS_SELENIUM_DEFAULT_TIMEOUT} | ||
|
||
TS_SELENIUM_LANGUAGE_SERVER_START_TIMEOUT: ${TestConstants.TS_SELENIUM_LANGUAGE_SERVER_START_TIMEOUT} | ||
TS_SELENIUM_LOAD_PAGE_TIMEOUT: ${TestConstants.TS_SELENIUM_LOAD_PAGE_TIMEOUT} | ||
TS_SELENIUM_START_WORKSPACE_TIMEOUT: ${TestConstants.TS_SELENIUM_START_WORKSPACE_TIMEOUT} | ||
TS_SELENIUM_WORKSPACE_STATUS_ATTEMPTS: ${TestConstants.TS_SELENIUM_WORKSPACE_STATUS_ATTEMPTS} | ||
TS_SELENIUM_WORKSPACE_STATUS_POLLING: ${TestConstants.TS_SELENIUM_WORKSPACE_STATUS_POLLING} | ||
|
||
######################################################## | ||
` | ||
|
||
console.log(launchInformation) | ||
}) | ||
|
||
runner.on('end', async function (test: mocha.Test) { | ||
// ensure that fired events done | ||
await driver.get().sleep(5000).catch(err => {throw err}) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's a mess. Please use |
||
|
||
// close driver | ||
await driver.get().quit().catch(err => { throw err }) | ||
}) | ||
|
||
|
||
runner.on('fail', async function (test: mocha.Test) { | ||
|
||
const reportDirPath: string = './report' | ||
const testFullTitle: string = test.fullTitle().replace(/\s/g, '_') | ||
const testTitle: string = test.title.replace(/\s/g, '_') | ||
|
||
const testReportDirPath: string = `${reportDirPath}/${testFullTitle}` | ||
const screenshotFileName: string = `${testReportDirPath}/screenshot-${testTitle}.png` | ||
const pageSourceFileName: string = `${testReportDirPath}/pagesource-${testTitle}.html` | ||
|
||
// create reporter dir if not exist | ||
await fs.exists(reportDirPath, async isDirExist => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am afraid, you have a race here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This one is still valid, right @Ohrimenko1988 ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. From Node.js v10.12 you can use recursive version of |
||
if (!isDirExist) { | ||
await fs.mkdir(reportDirPath, err => { | ||
if (err) { | ||
throw err | ||
} | ||
}) | ||
} | ||
}) | ||
|
||
// create dir for collected data if not exist | ||
await fs.exists(testReportDirPath, async isDirExist => { | ||
if (!isDirExist) { | ||
await fs.mkdir(testReportDirPath, err => { | ||
if (err) { | ||
throw err | ||
} | ||
}) | ||
} | ||
}) | ||
|
||
// take screenshot and write to file | ||
const screenshot: string = await driver.get().takeScreenshot().catch(err => { throw err }); | ||
const screenshotStream = fs.createWriteStream(screenshotFileName) | ||
screenshotStream.write(new Buffer(screenshot, 'base64')) | ||
screenshotStream.end() | ||
|
||
// take pagesource and write to file | ||
const pageSource: string = await driver.get().getPageSource().catch(err => { throw err }) | ||
const pageSourceStream = fs.createWriteStream(pageSourceFileName) | ||
pageSourceStream.write(new Buffer(pageSource)) | ||
pageSourceStream.end() | ||
|
||
}) | ||
} | ||
} | ||
|
||
module.exports = CheReporter; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this necessary? This is not TypeScript way of exporting modules |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
/********************************************************************* | ||
* Copyright (c) 2019 Red Hat, Inc. | ||
* | ||
* This program and the accompanying materials are made | ||
* available under the terms of the Eclipse Public License 2.0 | ||
* which is available at https://www.eclipse.org/legal/epl-2.0/ | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 | ||
**********************************************************************/ | ||
import 'chromedriver'; | ||
import 'reflect-metadata'; | ||
import { injectable, inject } from "inversify"; | ||
import { ThenableWebDriver, Builder } from "selenium-webdriver"; | ||
import { Driver } from './Driver'; | ||
import { Options } from 'selenium-webdriver/chrome'; | ||
import { TestConstants } from '../TestConstants'; | ||
|
||
@injectable() | ||
export class ChromeDriver implements Driver { | ||
private readonly driver: ThenableWebDriver; | ||
|
||
constructor() { | ||
const isHeadless: boolean = TestConstants.TS_SELENIUM_HEADLESS; | ||
let options: Options = new Options().addArguments('--no-sandbox') | ||
|
||
if (isHeadless) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe less code: let options = new Options().addArguments('--no-sandbox');
if (isHeadless) {
options = options.addArguments('headless'))
}
this.driver = new Builder()
.forBrowser('chrome')
.setChromeOptions(options)
.build(); |
||
options = options.addArguments('headless') | ||
} | ||
|
||
this.driver = new Builder() | ||
.forBrowser('chrome') | ||
.setChromeOptions(options) | ||
.build(); | ||
|
||
this.driver | ||
.manage() | ||
.window() | ||
.setSize(TestConstants.TS_SELENIUM_RESOLUTION_WIDTH, TestConstants.TS_SELENIUM_RESOLUTION_HEIGHT) | ||
} | ||
rhopp marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
get(): ThenableWebDriver { | ||
return this.driver | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
/********************************************************************* | ||
* Copyright (c) 2019 Red Hat, Inc. | ||
* | ||
* This program and the accompanying materials are made | ||
* available under the terms of the Eclipse Public License 2.0 | ||
* which is available at https://www.eclipse.org/legal/epl-2.0/ | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 | ||
**********************************************************************/ | ||
import { ThenableWebDriver } from "selenium-webdriver"; | ||
|
||
export interface Driver { | ||
get(): ThenableWebDriver | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is the reason to return There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Ohrimenko1988 Is there a reason for this? |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
/********************************************************************* | ||
* Copyright (c) 2019 Red Hat, Inc. | ||
* | ||
* This program and the accompanying materials are made | ||
* available under the terms of the Eclipse Public License 2.0 | ||
* which is available at https://www.eclipse.org/legal/epl-2.0/ | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 | ||
**********************************************************************/ | ||
import { Container } from "inversify"; | ||
import { Driver } from "./driver/Driver"; | ||
import { TYPES, CLASSES } from "./inversify.types"; | ||
import { ChromeDriver } from "./driver/ChromeDriver"; | ||
import { DriverHelper } from "./utils/DriverHelper"; | ||
import { LoginPage } from "./pageobjects/login/LoginPage"; | ||
import { SingleUserLoginPage } from "./pageobjects/login/SingleUserLoginPage"; | ||
import { Dashboard } from "./pageobjects/dashboard/Dashboard"; | ||
import { Workspaces } from "./pageobjects/dashboard/Workspaces"; | ||
import { NewWorkspace } from "./pageobjects/dashboard/NewWorkspace"; | ||
import { WorkspaceDetails } from "./pageobjects/dashboard/workspace-details/WorkspaceDetails"; | ||
import { WorkspaceDetailsPlugins } from "./pageobjects/dashboard/workspace-details/WorkspaceDetailsPlugins"; | ||
import { Ide } from "./pageobjects/ide/Ide"; | ||
import { TestWorkspaceUtil } from "./utils/workspace/TestWorkspaceUtil"; | ||
import { ProjectTree } from "./pageobjects/ide/ProjectTree"; | ||
import { Editor } from "./pageobjects/ide/Editor"; | ||
|
||
const e2eContainer = new Container(); | ||
|
||
e2eContainer.bind<Driver>(TYPES.Driver).to(ChromeDriver).inSingletonScope(); | ||
e2eContainer.bind<LoginPage>(TYPES.LoginPage).to(SingleUserLoginPage).inSingletonScope(); | ||
|
||
e2eContainer.bind<DriverHelper>(CLASSES.DriverHelper).to(DriverHelper).inSingletonScope(); | ||
e2eContainer.bind<Dashboard>(CLASSES.Dashboard).to(Dashboard).inSingletonScope(); | ||
e2eContainer.bind<Workspaces>(CLASSES.Workspaces).to(Workspaces).inSingletonScope(); | ||
e2eContainer.bind<NewWorkspace>(CLASSES.NewWorkspace).to(NewWorkspace).inSingletonScope(); | ||
e2eContainer.bind<WorkspaceDetails>(CLASSES.WorkspaceDetails).to(WorkspaceDetails).inSingletonScope(); | ||
e2eContainer.bind<WorkspaceDetailsPlugins>(CLASSES.WorkspaceDetailsPlugins).to(WorkspaceDetailsPlugins).inSingletonScope(); | ||
e2eContainer.bind<Ide>(CLASSES.Ide).to(Ide).inSingletonScope(); | ||
e2eContainer.bind<TestWorkspaceUtil>(CLASSES.TestWorkspaceUtil).to(TestWorkspaceUtil).inSingletonScope(); | ||
e2eContainer.bind<ProjectTree>(CLASSES.ProjectTree).to(ProjectTree).inSingletonScope(); | ||
e2eContainer.bind<Editor>(CLASSES.Editor).to(Editor).inSingletonScope(); | ||
|
||
|
||
|
||
export { e2eContainer } |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
/********************************************************************* | ||
* Copyright (c) 2019 Red Hat, Inc. | ||
* | ||
* This program and the accompanying materials are made | ||
* available under the terms of the Eclipse Public License 2.0 | ||
* which is available at https://www.eclipse.org/legal/epl-2.0/ | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 | ||
**********************************************************************/ | ||
|
||
const TYPES = { | ||
Driver: Symbol.for("Driver"), | ||
LoginPage: Symbol.for("LoginPage") | ||
} | ||
|
||
const CLASSES = { | ||
DriverHelper: "DriverHelper", | ||
Dashboard: "Dashboard", | ||
Workspaces: "Workspaces", | ||
NewWorkspace: "NewWorkspace", | ||
WorkspaceDetails: "WorkspaceDetails", | ||
WorkspaceDetailsPlugins: "WorkspaceDetailsPlugins", | ||
Ide: "Ide", | ||
TestWorkspaceUtil: "TestWorkspaceUtil", | ||
ProjectTree: "ProjectTree", | ||
Editor: "Editor", | ||
} | ||
|
||
export { TYPES, CLASSES }; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--require ts-node/register | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I strongly suggest to avoid this magic and call TypeScript compiler ( There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I have seen this problem when trying to consume this project on our side. So I'm running it in this way:
and this is mocha.opts
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Katka92 We're going to merge this one as it is right now and we can do this change inm the future, if needed. |
||
--timeout 1200000 | ||
--reporter 'driver/CheReporter.ts' | ||
-u tdd | ||
--spec tests/*.spec.ts | ||
rhopp marked this conversation as resolved.
Show resolved
Hide resolved
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How is this change related to this PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Ohrimenko1988 are you going to address this?