Skip to content
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

test(e2e): onboarding tests #162

Merged
merged 4 commits into from
Jan 7, 2025
Merged
Show file tree
Hide file tree
Changes from 3 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
6 changes: 6 additions & 0 deletions test/e2e/constants/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,9 @@ export const e2eTestDirPath = join(__dirname, '..')
* files outside of the e2e test directory.
*/
export const rootDirPath = join(__dirname, '../../..')

/**
* The path to the node home directory. This is where the Radicle node stores its
* configuration and data.
*/
export const nodeHomePath = process.env['RAD_HOME']
15 changes: 15 additions & 0 deletions test/e2e/helpers/actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import type { Workbench } from 'wdio-vscode-service'

/**
* Opens the Radicle view container in the sidebar, by clicking the radicle button in the
* activity bar.
*/
export async function openRadicleViewContainer(workbench: Workbench) {
const activityBar = workbench.getActivityBar()
await activityBar.wait()

const radicleViewControl = await activityBar.getViewControl('Radicle')
await radicleViewControl?.wait()

await radicleViewControl?.openView()
}
28 changes: 28 additions & 0 deletions test/e2e/helpers/assertions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { browser } from '@wdio/globals'
import type { Workbench } from 'wdio-vscode-service'

/**
* Asserts that the CLI Commands and Patches sections are visible in the sidebar. This is
* considered the default state when the workspace is open with a git and rad initialized
* repository.
*/
export async function expectStandardSidebarViewsToBeVisible(workbench: Workbench) {
const sidebarView = workbench.getSideBar().getContent()
await sidebarView.wait()

await browser.waitUntil(
async () => {
try {
await Promise.all([
sidebarView.getSection('CLI COMMANDS'),
sidebarView.getSection('PATCHES'),
])

return true
} catch {
return false
}
},
{ timeoutMsg: 'expected the standard sidebar views to be visible' },
)
}
21 changes: 21 additions & 0 deletions test/e2e/helpers/queries.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type { Workbench } from 'wdio-vscode-service'

/**
* Retrieves the welcome text content from the first section in the sidebar view.
*
* @example await getFirstWelcomeViewText(workbench) // ["Welcome to Radicle!", "Get started by ..."]
*
* @returns The text content found as an array of strings split by newlines. If no content is
* found, an empty array.
*/
export async function getFirstWelcomeViewText(workbench: Workbench) {
const sidebarView = workbench.getSideBar().getContent()
await sidebarView.wait()

const welcomeText =
(await (
await (await sidebarView.getSections())[0]?.findWelcomeContent()
)?.getTextSections()) ?? []

return welcomeText
}
147 changes: 89 additions & 58 deletions test/e2e/specs/onboarding.spec.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,34 @@
import path from 'node:path'
import { browser, expect } from '@wdio/globals'
import type { ViewSection, Workbench } from 'wdio-vscode-service'
import type { Workbench } from 'wdio-vscode-service'
import { $, cd } from 'zx'
import type * as VsCode from 'vscode'
import { e2eTestDirPath } from '../constants/config'
import isEqual from 'lodash/isEqual'
import { expectStandardSidebarViewsToBeVisible } from '../helpers/assertions'
import { openRadicleViewContainer } from '../helpers/actions'
import { getFirstWelcomeViewText } from '../helpers/queries'
import { e2eTestDirPath, nodeHomePath } from '../constants/config'

describe('Onboarding Flow', () => {
let workbench: Workbench

before(async () => {
await initGitRepo()
workbench = await browser.getWorkbench()
})

describe('VS Code, *before* the workspace is rad-initialized,', () => {
describe('VS Code, *before* Radicle is installed,', () => {
const tempPathToNodeHome = `${nodeHomePath}.temp`

before(async () => {
// Simulate radicle "not being installed" by renaming the node home directory
await $`mv ${nodeHomePath} ${tempPathToNodeHome}`
})

after(async () => {
await $`mv ${tempPathToNodeHome} ${nodeHomePath}`
await workbench.executeCommand('Developer: Reload Window')
})
maninak marked this conversation as resolved.
Show resolved Hide resolved

it('has our Radicle extension installed and available', async () => {
const extensions = await browser.executeWorkbench(
(vscode: typeof VsCode) => vscode.extensions.all,
Expand All @@ -31,68 +46,92 @@ describe('Onboarding Flow', () => {
expect(title).toBe('Radicle')
})

it('guides the user on how to rad-initialize their git repo', async () => {
it('instructs the user to install radicle', async () => {
await openRadicleViewContainer(workbench)

const welcomeText = await getFirstWelcomeViewText(workbench)
const buttonTitles = await getFirstWelcomeViewButtonTitles(workbench)

expect(welcomeText).toEqual([
/* eslint-disable max-len */
'The Git repository currently opened in your workspace is not yet initialized with Radicle.',
'To use Radicle with it, please run `rad init` in your terminal.',
'Once rad-initialized, this repo will have access to advanced source control, collaboration and project management capabilities powered by both Git and Radicle.',
'During this reversible rad-initializing process you also get to choose whether your repo will be private or public, among other options.',
'To learn more read the Radicle User Guide.',
'Failed resolving the Radicle CLI binary.',
"Please ensure it is installed on your machine and either that it is globally accessible in the shell as `rad` or that its path is correctly defined in the extension's settings.",
"Please expect the extention's capabilities to remain severely limited until this issue is resolved.",
/* eslint-enable max-len */
])

expect(welcomeText.some((text) => text.includes('rad init'))).toBe(true)
expect(buttonTitles).toEqual(['Troubleshoot'])
})
})

describe('VS Code, *after* the workspace is rad-initialized,', () => {
let cliCommandsSection: ViewSection
describe('VS Code, *before* the workspace is git-initialized,', () => {
it('guides the user on how to git-initialize their workspace', async () => {
await openRadicleViewContainer(workbench)

await browser.waitUntil(async () => {
const welcomeText = await getFirstWelcomeViewText(workbench)
const welcomeButtonTitles = await getFirstWelcomeViewButtonTitles(workbench)

return (
isEqual(welcomeText, [
/* eslint-disable max-len */
'The folder currently opened in your workspace is not a Git code repository.',
'In order to use Radicle with it, this folder must first be initialized as a Git code repository.',
'To learn more about how to use Git and source control in VS Code read the docs.',
/* eslint-enable max-len */
]) &&
isEqual(welcomeButtonTitles, [
'Initialize Repository With Git',
'Choose a Different Folder',
])
)
})
})
})

describe('VS Code, *before* the workspace is rad-initialized,', () => {
before(async () => {
await $`rad init --private --default-branch main --name "A_test_blog" --description "Some repo" --no-confirm --verbose`
await initGitRepo()
})

it('guides the user on how to rad-initialize their git repo', async () => {
await openRadicleViewContainer(workbench)
const sidebarView = workbench.getSideBar().getContent()
await sidebarView.wait()

cliCommandsSection = await sidebarView.getSection('CLI COMMANDS')
await cliCommandsSection.collapse()
await browser.waitUntil(async () => {
const welcomeText = await getFirstWelcomeViewText(workbench)

return isEqual(welcomeText, [
/* eslint-disable max-len */
'The Git repository currently opened in your workspace is not yet initialized with Radicle.',
'To use Radicle with it, please run `rad init` in your terminal.',
'Once rad-initialized, this repo will have access to advanced source control, collaboration and project management capabilities powered by both Git and Radicle.',
'During this reversible rad-initializing process you also get to choose whether your repo will be private or public, among other options.',
'To learn more read the Radicle User Guide.',
/* eslint-enable max-len */
])
})
})
})

const patchesSection = await sidebarView.getSection('PATCHES')
await patchesSection.collapse()
describe('VS Code, *after* the workspace is rad-initialized,', () => {
before(async () => {
await $`rad init --private --default-branch main --name "A_test_blog" --description "Some repo" --no-confirm --verbose`
await workbench.executeCommand('Developer: Reload Window')
})

it('hides the non rad-initialized guide', async () => {
const welcomeText = await getFirstWelcomeViewText(workbench)
await browser.waitUntil(async () => {
const welcomeText = await getFirstWelcomeViewText(workbench)

expect(welcomeText.some((text) => text.includes('rad init'))).not.toBe(true)
return welcomeText.some((text) => text.includes('rad init')) === false
})
})

it('shows the CLI Commands section', async () => {
await cliCommandsSection.expand()
// Fixes flakiness on macOS CI
await browser.pause(100)

const welcomeContent = await cliCommandsSection?.findWelcomeContent()
const welcomeText = (await welcomeContent?.getTextSections()) ?? []
const buttons = (await welcomeContent?.getButtons()) ?? []
const buttonTitles = await Promise.all(
buttons.map(async (button) => await button.getTitle()),
)

expect(
welcomeText.some((text) =>
/Use the buttons below to perform common interactions with the Radicle network./i.test(
text,
),
),
).toBe(true)
it('shows the standard sidebar views', async () => {
const sidebarView = workbench.getSideBar().getContent()
await sidebarView.wait()

expect(buttonTitles).toEqual(['Sync', 'Fetch', 'Announce'])
await expectStandardSidebarViewsToBeVisible(workbench)
})
})
})
Expand All @@ -111,24 +150,16 @@ async function initGitRepo() {
await $`git commit -m 'adds readme' --no-gpg-sign`
}

async function openRadicleViewContainer(workbench: Workbench) {
const activityBar = workbench.getActivityBar()
await activityBar.wait()

const radicleViewControl = await activityBar.getViewControl('Radicle')
await radicleViewControl?.wait()

await radicleViewControl?.openView()
}

async function getFirstWelcomeViewText(workbench: Workbench) {
async function getFirstWelcomeViewButtonTitles(workbench: Workbench) {
const sidebarView = workbench.getSideBar().getContent()
await sidebarView.wait()

const welcomeText =
(await (
await (await sidebarView.getSections())[0]?.findWelcomeContent()
)?.getTextSections()) ?? []
const buttons =
(await (await (await sidebarView.getSections())[0]?.findWelcomeContent())?.getButtons()) ??
[]
const buttonTitles = await Promise.all(
buttons.map(async (button) => await button.getTitle()),
)

return welcomeText
return buttonTitles
}
Loading