diff --git a/.github/workflows/integrations.yml b/.github/workflows/integrations.yml new file mode 100644 index 0000000000..4f81a92057 --- /dev/null +++ b/.github/workflows/integrations.yml @@ -0,0 +1,43 @@ +name: GithubIntegrations +on: + schedule: + # Runs at 5 AM UTC every day. We can change this to whatever we need or want + - cron: '0 5 * * *' +jobs: + setup-and-test: + runs-on: ubuntu-latest + timeout-minutes: 60 + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + - name: Cache node modules + uses: actions/cache@v4 + with: + path: | + common/temp + key: ${{ runner.os }}-build-node-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-build-node-${{ hashFiles('**/pnpm-lock.yaml') }} + - name: Checking for mis-matching dependencies... + run: node common/scripts/install-run-rush.js check + + - name: Installing... + run: node common/scripts/install-run-rush.js install + + - name: Install Playwright + run: | + cd ./tests/sanity + node ../../common/scripts/install-run-rushx.js ci + - name: Run UI tests + run: | + cd ./tests/sanity + node ../../common/scripts/install-run-rushx.js staging-uitest + env: + TESTING_GH_TOKEN: ${{ secrets.TESTING_GH_TOKEN }} + TESTING_GH_OWNER: ${{ secrets.TESTING_GH_OWNER }} diff --git a/tests/sanity/.env b/tests/sanity/.env index 94c54e112f..d84a132bc6 100644 --- a/tests/sanity/.env +++ b/tests/sanity/.env @@ -1,5 +1,6 @@ PLATFORM_URI='http://localhost:8083' PLATFORM_TRANSACTOR='ws://localhost:3334' +STAGING_URL='https://front.hc.engineering' PLATFORM_USER='user1' PLATFORM_USER_SECOND='user2' PLATFORM_TOKEN='eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJlbWFpbCI6InVzZXIxIiwid29ya3NwYWNlIjoic2FuaXR5LXdzIn0.hfUCqePHO-WNps2by4B-CYGKIpDpLG0WVCUUtU-SVI4' diff --git a/tests/sanity/package.json b/tests/sanity/package.json index 419057de91..2f25891c13 100644 --- a/tests/sanity/package.json +++ b/tests/sanity/package.json @@ -20,6 +20,7 @@ "ci": "playwright install --with-deps chromium", "test": "", "uitest": "cross-env LOCAL_URL=http://localhost:3003/ DEV_URL= playwright test -c ./tests/playwright.config.ts", + "staging-uitest": "cross-env PLATFORM_URI=https://front.hc.engineering/ playwright test -c ./tests/playwright.config.ts --grep @staging", "dev-uitest": "cross-env PLATFORM_URI=http://localhost:8080 PLATFORM_TRANSACTOR=ws://localhost:3333 SETTING=storage-dev.json SETTING_SECOND=storageSecond-dev.json DEV_URL=http://localhost:8080/account playwright test -c ./tests/playwright.config.ts", "debug": "playwright test -c ./tests/playwright.config.ts --debug --headed", "dev-debug": "cross-env PLATFORM_URI=http://localhost:8080 PLATFORM_TRANSACTOR=ws://localhost:3333 SETTING=storage-dev.json SETTING_SECOND=storageSecond-dev.json playwright test -c ./tests/playwright.config.ts --debug --headed", diff --git a/tests/sanity/tests/API/GithubIntegration.ts b/tests/sanity/tests/API/GithubIntegration.ts new file mode 100644 index 0000000000..8066a0c8f1 --- /dev/null +++ b/tests/sanity/tests/API/GithubIntegration.ts @@ -0,0 +1,76 @@ +import { APIRequestContext } from '@playwright/test' + +export class GithubIntegration { + private readonly request: APIRequestContext + private readonly baseUrl: string + private readonly githubToken: string + private readonly repoOwner: string + + constructor (request: APIRequestContext) { + this.request = request + this.baseUrl = 'https://api.github.com' + + this.githubToken = process.env.TESTING_GH_TOKEN as string + this.repoOwner = process.env.TESTING_GH_OWNER as string + + if (typeof this.githubToken !== 'string' || this.githubToken.trim() === '') { + throw new Error('Environment variable TESTING_GH_TOKEN is not set or empty.') + } + if (typeof this.repoOwner !== 'string' || this.repoOwner.trim() === '') { + throw new Error('Environment variable TESTING_GH_OWNER is not set or empty.') + } + } + + async createGitHubRepository (repoName: string, description: string = '', isPrivate: boolean = false): Promise { + const githubToken = this.githubToken + const url = `${this.baseUrl}/user/repos` + const payload = { + name: repoName, + description, + private: isPrivate + } + const headers = { + Authorization: `token ${githubToken}`, + Accept: 'application/vnd.github.v3+json', + 'Content-Type': 'application/json' + } + const response = await this.request.post(url, { data: payload, headers }) + if (response.status() !== 201) { + throw new Error(`Failed to create repository: ${response.status()} ${response.statusText()}`) + } + return await response.json() + } + + async createGitHubIssue (repoName: string, issueTitle: string, issueBody: string): Promise { + const githubToken = this.githubToken + const url = `${this.baseUrl}/repos/${this.repoOwner}/${repoName}/issues` + const payload = { + title: issueTitle, + body: issueBody + } + const headers = { + Authorization: `token ${githubToken}`, + Accept: 'application/vnd.github.v3+json', + 'Content-Type': 'application/json' + } + const response = await this.request.post(url, { data: payload, headers }) + if (response.status() !== 201) { + throw new Error(`Failed to create issue: ${response.status()} ${response.statusText()}`) + } + return await response.json() + } + + async deleteGitHubRepository (repoName: string): Promise { + const githubToken = this.githubToken + const url = `${this.baseUrl}/repos/${this.repoOwner}/${repoName}` + const headers = { + Authorization: `token ${githubToken}`, + Accept: 'application/vnd.github.v3+json', + 'Content-Type': 'application/json' + } + const response = await this.request.delete(url, { headers }) + if (response.status() !== 204) { + throw new Error(`Failed to delete repository: ${response.status()} ${response.statusText()}`) + } + } +} diff --git a/tests/sanity/tests/integrations/github-integrations.spec.ts b/tests/sanity/tests/integrations/github-integrations.spec.ts new file mode 100644 index 0000000000..36f1ab3aef --- /dev/null +++ b/tests/sanity/tests/integrations/github-integrations.spec.ts @@ -0,0 +1,33 @@ +import { test } from '@playwright/test' +// import { LoginPage } from '../model/login-page' +import { StagingUrl } from '../utils' +// import { CommonTrackerPage } from '../model/tracker/common-tracker-page' +// import { SignUpPage } from '../model/signup-page' +// import { TrackerNavigationMenuPage } from '../model/tracker/tracker-navigation-menu-page' +// import { SelectWorkspacePage } from '../model/select-workspace-page' +// import { GithubIntegration } from '../API/GithubIntegration' +// import { faker } from '@faker-js/faker' + +test.describe('Github integrations @staging', () => { + // let githubIntegrations: GithubIntegration + + test.beforeEach(async ({ page, request }) => { + // loginPage = new LoginPage(page) + // commonTrackerPage = new CommonTrackerPage(page) + // signupPage = new SignUpPage(page) + // trackerNavigationMenuPage = new TrackerNavigationMenuPage(page) + // selectWorkspacePage = new SelectWorkspacePage(page) + // githubIntegrations = new GithubIntegration(request) + // const repoName = faker.word.words(1) + // const issueTitle = faker.word.words(4) + // const issueBody = faker.word.words(10) + // await githubIntegrations.createGitHubRepository(repoName) + // await githubIntegrations.createGitHubIssue(repoName, issueTitle, issueBody) + + await (await page.goto(`${StagingUrl}`))?.finished() + await page.waitForTimeout(100) + // await githubIntegrations.deleteGitHubRepository(repoName) + }) + + test('user can integrate using github @staging', async ({ page }) => {}) +}) diff --git a/tests/sanity/tests/utils.ts b/tests/sanity/tests/utils.ts index beb034913e..bf997cc753 100644 --- a/tests/sanity/tests/utils.ts +++ b/tests/sanity/tests/utils.ts @@ -13,6 +13,7 @@ export const PlatformSettingSecond = process.env.SETTING_SECOND as string export const DefaultWorkspace = 'SanityTest' export const LocalUrl = process.env.LOCAL_URL as string export const DevUrl = process.env.DEV_URL as string +export const StagingUrl = process.env.STAGING_URL as string export function generateTestData (): TestData { const generateWordStartingWithA = (): string => {