-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 91f2030
Showing
27 changed files
with
740 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
root = true | ||
|
||
[*] | ||
tab_width = 2 | ||
indent_size = 2 | ||
# charset = utf-8 | ||
# end_of_line = lf | ||
# indent_size = 4 | ||
# indent_style = space | ||
# insert_final_newline = true | ||
# max_line_length = 120 | ||
# tab_width = 4 | ||
# trim_trailing_whitespace = true | ||
|
||
[*.ts] | ||
indent_size = 2 | ||
|
||
[*.scss] | ||
indent_size = 2 | ||
|
||
[{*.ats, *.ts}] | ||
# indent_size = 2 | ||
# tab_width = 2 | ||
|
||
[{*.js, *.cjs}] | ||
# indent_size = 2 | ||
# tab_width = 2 | ||
|
||
[{*.sht, *.html, *.shtm, *.shtml, *.htm, *.ng}] | ||
# indent_size = 2 | ||
# tab_width = 2 | ||
|
||
[{.analysis_options, *.yml, *.yaml}] | ||
# indent_size = 2 | ||
|
||
[{.babelrc, .prettierrc, .stylelintrc, .eslintrc, jest.config, *.json, *.jsb3, *.jsb2, *.bowerrc}] | ||
# indent_size = 2 | ||
|
||
[vue.config.js] | ||
indent_size = 2 | ||
tab_width = 2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
name: Test Crawlab | ||
on: | ||
push: | ||
branches: [ main ] | ||
pull_request: | ||
branches: [ main ] | ||
jobs: | ||
test: | ||
services: | ||
crawlab: | ||
image: crawlabteam/crawlab:develop | ||
ports: | ||
- 8080:8080 | ||
mongo: | ||
image: mongo:latest | ||
ports: | ||
- 27017:27017 | ||
timeout-minutes: 60 | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v4 | ||
- uses: actions/setup-node@v4 | ||
with: | ||
node-version: lts/* | ||
- name: Install dependencies | ||
run: npm ci | ||
- name: Install Playwright Browsers | ||
run: npx playwright install --with-deps | ||
- name: Run Playwright tests | ||
run: npx playwright test | ||
- uses: actions/upload-artifact@v4 | ||
if: ${{ !cancelled() }} | ||
with: | ||
name: playwright-report | ||
path: playwright-report/ | ||
retention-days: 30 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
node_modules/ | ||
/test-results/ | ||
/playwright-report/ | ||
/blob-report/ | ||
/playwright/.cache/ | ||
.idea/ | ||
.env |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
{ | ||
"semi": true, | ||
"trailingComma": "es5", | ||
"singleQuote": true, | ||
"printWidth": 80, | ||
"tabWidth": 2, | ||
"useTabs": false, | ||
"bracketSpacing": true, | ||
"jsxBracketSameLine": false, | ||
"arrowParens": "avoid", | ||
"endOfLine": "lf" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
# Crawlab E2E Tests | ||
|
||
This repository contains end-to-end tests for Crawlab. | ||
|
||
## Getting Started | ||
|
||
``` | ||
e2e/ | ||
├───fixtures # Test data (JSON files or static data) | ||
├───page-objects # Page Object Model files for different pages | ||
├───tests # Your actual test cases organized by feature or page | ||
└───utils # Utility functions and reusable helpers | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
{ | ||
"adminUser": { | ||
"username": "admin", | ||
"password": "admin" | ||
}, | ||
"invalidUser": { | ||
"username": "invalid", | ||
"password": "invalid" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
{ | ||
"name": "@crawlab/e2e-tests", | ||
"private": true, | ||
"version": "1.0.0", | ||
"description": "", | ||
"main": "index.js", | ||
"scripts": { | ||
"test": "npx playwright test", | ||
"test:headed": "npx playwright test --headed", | ||
"test:debug": "npx playwright test --debug" | ||
}, | ||
"devDependencies": { | ||
"@playwright/test": "^1.48.1", | ||
"@types/node": "^22.7.7", | ||
"dotenv": "^16.4.5" | ||
} | ||
} |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import { Page } from '@playwright/test'; | ||
import ListLayoutPage from '@/page-objects/layout/listLayoutPage'; | ||
import NormalLayoutPage from '@/page-objects/layout/normalLayoutPage'; | ||
|
||
export default abstract class DetailLayoutPage<T extends ListLayoutPage> extends NormalLayoutPage { | ||
private listPage: T; | ||
|
||
protected abstract getListPage(): T; | ||
|
||
constructor(page: Page) { | ||
super(page); | ||
this.listPage = this.getListPage(); | ||
} | ||
|
||
protected detailContainer = '.detail-layout'; | ||
protected backButton = '[data-test="back-btn"]'; | ||
protected saveButton = '[data-test="save-btn"]'; | ||
protected activeTabSelector = '.nav-tabs .el-menu-item.is-active'; | ||
|
||
async navigate(rowIndex?: number) { | ||
await super.navigate(); | ||
await this.listPage.navigate(); | ||
await this.listPage.navigateToDetail(rowIndex || 0); | ||
await this.waitForPageLoad(); | ||
} | ||
|
||
async waitForPageLoad() { | ||
await this.page.waitForSelector(this.detailContainer); | ||
} | ||
|
||
async getActiveTabName() { | ||
const activeTab = this.page.locator(this.activeTabSelector); | ||
return activeTab.textContent(); | ||
} | ||
|
||
async switchToTab(tabName: string) { | ||
await this.page.click(`.nav-tabs [data-test="${tabName}"]`); | ||
} | ||
|
||
async save() { | ||
await this.page.click(this.saveButton); | ||
} | ||
|
||
async goBack() { | ||
await this.page.click(this.backButton); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import NormalLayoutPage from '@/page-objects/layout/normalLayoutPage'; | ||
|
||
export default abstract class ListLayoutPage extends NormalLayoutPage { | ||
protected abstract path: string; | ||
|
||
protected listContainer = '.list-layout'; | ||
protected createButton = '#add-btn'; | ||
protected searchInput = '#filter-search .el-input input'; | ||
protected tableRows = '.list-layout table tbody tr'; | ||
protected viewButton = '.view-btn'; | ||
|
||
async navigate() { | ||
await super.navigate(); | ||
await this.page.goto(this.path); | ||
await this.waitForPageLoad(); | ||
} | ||
|
||
async waitForPageLoad() { | ||
await this.page.waitForSelector(this.listContainer); | ||
} | ||
|
||
async navigateToDetail(rowIndex: number) { | ||
const row = this.page.locator(this.tableRows).nth(rowIndex); | ||
await row.locator(this.viewButton).click(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import { Page } from '@playwright/test'; | ||
import { LoginPage } from '@/page-objects/login/loginPage'; | ||
import userData from '@/fixtures/userData.json'; | ||
|
||
export default abstract class NormalLayoutPage { | ||
protected page: Page; | ||
protected loginPage: LoginPage; | ||
|
||
constructor(page: Page) { | ||
this.page = page; | ||
this.loginPage = new LoginPage(page); | ||
} | ||
|
||
protected edition = '.sidebar .logo-sub-title .logo-sub-title-block:nth-child(1)'; | ||
|
||
async navigate() { | ||
await this.page.goto('/'); // Navigate to the base URL | ||
const isLoggedIn = await this.checkLoginStatus(); | ||
if (!isLoggedIn) { | ||
await this.performLogin(); | ||
} | ||
} | ||
|
||
private async checkLoginStatus(): Promise<boolean> { | ||
return await this.page.evaluate(() => { | ||
const token = localStorage.getItem('jwt_token'); | ||
return !!token; | ||
}); | ||
} | ||
|
||
private async performLogin() { | ||
await this.loginPage.navigate(); | ||
await this.loginPage.login(userData.adminUser.username, userData.adminUser.password); | ||
// After successful login, store the JWT token | ||
await this.storeJwtToken(); | ||
} | ||
|
||
private async storeJwtToken() { | ||
// Assuming the JWT token is stored in localStorage after login | ||
// You may need to adjust this based on your actual implementation | ||
await this.page.evaluate(() => { | ||
const token = localStorage.getItem('your_jwt_token_key'); | ||
if (token) { | ||
localStorage.setItem('jwt_token', token); | ||
} | ||
}); | ||
} | ||
|
||
abstract waitForPageLoad(): Promise<void>; | ||
|
||
async getEdition() { | ||
return (await this.page.locator(this.edition).textContent())?.trim(); | ||
} | ||
|
||
async isPro(): Promise<boolean> { | ||
const edition = await this.getEdition(); | ||
if (!edition) return false; | ||
return ['Pro', '专业版'].some(value => value.includes(edition)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import { Page } from '@playwright/test'; | ||
|
||
export class LoginPage { | ||
private page: Page; | ||
private usernameField = 'input[name="username"]'; | ||
private passwordField = 'input[name="password"]'; | ||
private submitButton = 'button[name="submit"]'; | ||
public errorMessage = '.el-message--error'; | ||
|
||
constructor(page: Page) { | ||
this.page = page; | ||
} | ||
|
||
async navigate() { | ||
await this.page.goto('/#/login'); | ||
await this.waitForPageLoad(); | ||
} | ||
|
||
async waitForPageLoad() { | ||
await this.page.waitForSelector(this.usernameField); | ||
} | ||
|
||
async login(username: string, password: string) { | ||
await this.enterUsername(username); | ||
await this.enterPassword(password); | ||
await this.submit(); | ||
} | ||
|
||
async enterUsername(username: string) { | ||
await this.page.fill(this.usernameField, username); | ||
} | ||
|
||
async enterPassword(password: string) { | ||
await this.page.fill(this.passwordField, password); | ||
} | ||
|
||
async submit() { | ||
await this.page.click(this.submitButton); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import { NodeListPage } from '@/page-objects/node/nodeListPage'; | ||
import DetailLayoutPage from '@/page-objects/layout/detailLayoutPage'; | ||
|
||
export class NodeDetailPage extends DetailLayoutPage<NodeListPage> { | ||
private nameField = '.form-item[data-test="name"] input'; | ||
private typeSelector = '.form-item[data-test="type"] .el-tag'; | ||
private enabledSwitch = '.form-item[data-test="enabled"] .el-switch__input'; | ||
private maxRunnersField = '.form-item[data-test="max_runners"] input'; | ||
private descriptionField = '.form-item[data-test="description"] textarea'; | ||
private currentMetricsSelector = '.current-metrics'; | ||
private monitoringTabSelector = '.nav-tabs [data-test="monitoring"]'; | ||
|
||
getListPage(): NodeListPage { | ||
return new NodeListPage(this.page); | ||
} | ||
|
||
async isMonitoringTabDisabled() { | ||
const monitoringTab = this.page.locator(this.monitoringTabSelector); | ||
if (!monitoringTab) return null; | ||
return await monitoringTab.getAttribute('class').then(cls => cls?.includes('is-disabled')); | ||
} | ||
|
||
async getNodeName() { | ||
return this.page.inputValue(this.nameField); | ||
} | ||
|
||
async getNodeType() { | ||
return this.page.locator(this.typeSelector)?.textContent(); | ||
} | ||
|
||
async isNodeEnabled() { | ||
const ariaChecked = await this.page.locator(this.enabledSwitch)?.getAttribute('aria-checked'); | ||
return ariaChecked === 'true'; | ||
} | ||
|
||
async getNodeMaxRunners() { | ||
return this.page.inputValue(this.maxRunnersField); | ||
} | ||
|
||
async getNodeDescription() { | ||
return this.page.inputValue(this.descriptionField); | ||
} | ||
|
||
async getCurrentMetrics() { | ||
return this.page.locator(this.currentMetricsSelector)?.textContent(); | ||
} | ||
} |
Oops, something went wrong.