Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
ebe6f65
add dvc python path into user settings
mattseddon Jul 8, 2022
5d0d9e9
use tree for the table role (update to React types)
mattseddon Jul 8, 2022
18e8d4b
add end to end test workflow
mattseddon Jul 8, 2022
28cee39
try mac for screenshot
mattseddon Jul 8, 2022
3aa068c
increase timeout and take screenshot
mattseddon Jul 8, 2022
f1856eb
add screenshots directory to gitignore
mattseddon Jul 8, 2022
2cc9dfc
pull data once on startup
mattseddon Jul 8, 2022
764640b
explicitly set timeout in before and wait step
mattseddon Jul 8, 2022
a9bc755
increase timeout of experiment
mattseddon Jul 8, 2022
2dcfe05
fix up pulling all data before proceeding
mattseddon Jul 8, 2022
b917f84
fix timeouts of startup
mattseddon Jul 8, 2022
86bbe58
split wait for blocks
mattseddon Jul 8, 2022
f7a84a4
refactor waiting for the cli functions
mattseddon Jul 8, 2022
6a24e45
try ubuntu
mattseddon Jul 8, 2022
97eb9f2
reduce number of epochs
mattseddon Jul 8, 2022
2a58c65
try and debug if rows are being found or not
mattseddon Jul 8, 2022
adf3176
check on expand buttons
mattseddon Jul 8, 2022
6010bf0
check on contract buttons
mattseddon Jul 8, 2022
c508884
take screenshots
mattseddon Jul 8, 2022
ecc9794
checkout the entire git history
mattseddon Jul 8, 2022
d604662
fix action
mattseddon Jul 8, 2022
b244499
remove all debugging code
mattseddon Jul 8, 2022
8706cc3
Merge branch 'main' of https://github.com/iterative/vscode-dvc into r…
mattseddon Jul 8, 2022
7e5cf62
revert dvc files
mattseddon Jul 8, 2022
b77a11a
add end to end into continuous integration
mattseddon Jul 11, 2022
1d2303b
use yarn install for windows
mattseddon Jul 11, 2022
5e965cf
remove macos from cross-platform tests
mattseddon Jul 11, 2022
edd489e
improve test reliability
mattseddon Jul 11, 2022
cf52e17
remove end to end workflow
mattseddon Jul 12, 2022
a87b8e1
Merge branch 'main' into run-e2e
mattseddon Jul 12, 2022
01e59a9
Merge branch 'main' into run-e2e
mattseddon Jul 12, 2022
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
18 changes: 18 additions & 0 deletions .github/workflows/continuous-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ jobs:
with:
fetch-depth: 0

- name: Setup Python environment
uses: actions/setup-python@v4
with:
python-version: '3.9'

- name: Setup Node.js environment
uses: actions/setup-node@v3
with:
Expand Down Expand Up @@ -55,3 +60,16 @@ jobs:
storybookBuildDir: 'webview/storybook-static'
exitOnceUploaded: true
autoAcceptChanges: 'main'

- name: Test E2E
uses: GabrielBB/xvfb-action@v1
with:
run: yarn test:e2e
options: '-screen 0 1600x1200x24'
- uses: actions/upload-artifact@v3
if: failure()
with:
name: screenshots
path: |
extension/src/test/e2e/screenshots
extension/src/test/e2e/logs
2 changes: 1 addition & 1 deletion .github/workflows/cross-platform-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
timeout-minutes: 20
strategy:
matrix:
os: [macOS-latest, windows-latest]
os: [windows-latest]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[F] By removing the less valuable macOS-latest tests we make get back more minutes than we expend running the E2E tests in the main workflow.

steps:
- name: Checkout
uses: actions/checkout@v3
Expand Down
8 changes: 4 additions & 4 deletions demo/training_metrics.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"step": 14,
"loss": 0.9596208930015564,
"acc": 0.7735
}
"step": 14,
"loss": 0.9596208930015564,
"acc": 0.7735
}
1 change: 1 addition & 0 deletions extension/.gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
*.vsix
.vscode-test
.wdio-vscode-service
screenshots
README.md
LICENSE
CHANGELOG.md
Expand Down
6 changes: 1 addition & 5 deletions extension/src/python/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { join } from 'path'
import { getVenvBinPath } from './path'
import { getProcessPlatform } from '../env'
import { exists } from '../fileSystem'
import { createProcessWithOutput } from '../processExecution'
Expand All @@ -11,11 +12,6 @@ const installPackages = (cwd: string, pythonBin: string, ...args: string[]) => {
})
}

export const getVenvBinPath = (cwd: string, envDir: string, name: string) =>
getProcessPlatform() === 'win32'
? join(cwd, envDir, 'Scripts', `${name}.exe`)
: join(cwd, envDir, 'bin', name)

export const setupVenv = async (
cwd: string,
envDir: string,
Expand Down
7 changes: 7 additions & 0 deletions extension/src/python/path.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { join } from 'path'
import { getProcessPlatform } from '../env'

export const getVenvBinPath = (cwd: string, envDir: string, name: string) =>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[F] This needs to be separated so we don't have to require 'vscode'

getProcessPlatform() === 'win32'
? join(cwd, envDir, 'Scripts', `${name}.exe`)
: join(cwd, envDir, 'bin', name)
2 changes: 1 addition & 1 deletion extension/src/test/cli/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { CliExecutor } from '../../cli/executor'
import { CliReader } from '../../cli/reader'
import { Config } from '../../config'
import { exists } from '../../fileSystem'
import { getVenvBinPath } from '../../python'
import { getVenvBinPath } from '../../python/path'
import { dvcDemoPath } from '../util'

const config = {
Expand Down
37 changes: 25 additions & 12 deletions extension/src/test/e2e/extension.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,27 @@ import {
closeAllEditors,
dismissAllNotifications,
getDVCActivityBarIcon,
waitForDvcToFinish,
waitForViewContainerToLoad
} from './util'
import { ExperimentsWebview } from './pageObjects/experimentsWebview'
import { PlotsWebview } from './pageObjects/plotsWebview'
import { delay } from '../../util/time'

suite('DVC Extension For Visual Studio Code', () => {
before('should finish loading the extension', async () => {
before('should finish loading the extension', async function () {
this.timeout(240000)
await waitForViewContainerToLoad()
return dismissAllNotifications()
})

// avoid killing any background process after experiments have finished run
after(() => delay(30000))
after(function () {
this.timeout(60000)
return waitForDvcToFinish()
})

afterEach(() => browser.switchToFrame(null))
afterEach(function () {
return browser.switchToFrame(null)
})

describe('Activity Bar', () => {
it('should show the DVC Icon', async () => {
Expand All @@ -35,7 +40,7 @@ suite('DVC Extension For Visual Studio Code', () => {

await workbench.executeCommand('DVC: Show Experiments')

await webview.open()
await webview.focus()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[F] These seem like better names to me because the methods don't actually open/close the webview


await browser.waitUntil(async () => {
const table = await webview.table$
Expand All @@ -44,15 +49,15 @@ suite('DVC Extension For Visual Studio Code', () => {

expect(await webview.table$$).toHaveLength(1)

await webview.close()
await webview.unfocus()
})

it('should update with a new row for each checkpoint when an experiment is running', async () => {
const workbench = await browser.getWorkbench()
const epochs = 15
await workbench.executeCommand('DVC: Reset and Run Experiment')

await webview.open()
await webview.focus()

await browser.waitUntil(() => webview.expandAllRows())

Expand All @@ -66,13 +71,19 @@ suite('DVC Extension For Visual Studio Code', () => {
const currentRows = await webview.row$$
return currentRows.length >= initialRows.length + epochs
},
{ timeout: 120000 }
{ interval: 5000, timeout: 180000 }
)

await webview.unfocus()
await waitForDvcToFinish()
await webview.focus()

const finalRows = await webview.row$$

expect(finalRows.length).toStrictEqual(initialRows.length + epochs)
await webview.close()
await webview.unfocus()
await waitForDvcToFinish()
await workbench.executeCommand('Terminal: Kill All Terminals')
}).timeout(180000)
})

Expand All @@ -87,7 +98,9 @@ suite('DVC Extension For Visual Studio Code', () => {
const workbench = await browser.getWorkbench()
await workbench.executeCommand('DVC: Show Plots')

await webview.open()
await waitForDvcToFinish()

await webview.focus()

await browser.waitUntil(async () => {
return (await webview.vegaVisualization$$.length) === 6
Expand All @@ -101,7 +114,7 @@ suite('DVC Extension For Visual Studio Code', () => {
expect(plotNotEmpty).toBe(true)
}

await webview.close()
await webview.unfocus()
})
})
})
4 changes: 2 additions & 2 deletions extension/src/test/e2e/pageObjects/baseWebview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export class BaseWebview extends BasePage<
this.locatorKey = locatorKey
}

public async open() {
public async focus() {
const webviewContainer = await this.outerFrame$

await this.outerFrame$.waitForDisplayed()
Expand All @@ -31,7 +31,7 @@ export class BaseWebview extends BasePage<
return browser.switchToFrame(webviewInner)
}

public async close() {
public async unfocus() {
await browser.switchToFrame(null)
await browser.switchToFrame(null)
}
Expand Down
2 changes: 1 addition & 1 deletion extension/src/test/e2e/pageObjects/experimentsWebview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export class ExperimentsWebview extends BaseWebview {
public async expandAllRows() {
const expandRowButtons = await this.expandRowButton$$
for (const button of expandRowButtons) {
button.click()
await button.click()
}
return expandRowButtons.length === 0
}
Expand Down
2 changes: 1 addition & 1 deletion extension/src/test/e2e/pageObjects/locators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export const experiments = {
...webview,
expandRowButton: 'button[title="Expand Row"]',
row: '[role=row]',
table: '[role=table]'
table: '[role=tree]'
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[F] This changed when we move up to v18 of React

}

export const plots = {
Expand Down
67 changes: 51 additions & 16 deletions extension/src/test/e2e/util.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { ChainablePromiseArray, ElementArray } from 'webdriverio'
import { ViewControl } from 'wdio-vscode-service'

export const dismissAllNotifications = () =>
browser.waitUntil(async () => {
const findProgressBars = (): ChainablePromiseArray<ElementArray> =>
$$('.monaco-progress-container')

export const dismissAllNotifications = async (): Promise<void> => {
await browser.waitUntil(async () => {
const workbench = await browser.getWorkbench()
const notifications = await workbench.getNotifications()
for (const n of notifications) {
Expand All @@ -10,6 +14,23 @@ export const dismissAllNotifications = () =>
const openNotifications = await workbench.getNotifications()
return openNotifications.length === 0
})
}

const dvcIsWorking = async (): Promise<boolean> => {
const workbench = await browser.getWorkbench()
const statusBar = workbench.getStatusBar()
const statusBarItems = await statusBar.getItems()
return statusBarItems.some(
statusBarItem =>
statusBarItem.includes('loading~spin') && statusBarItem.includes('DVC')
)
}

export const waitForDvcToFinish = async (): Promise<void> => {
await browser.waitUntil(async () => !(await dvcIsWorking()), {
timeout: 60000
})
}

export const getDVCActivityBarIcon = async (): Promise<ViewControl> => {
const workbench = await browser.getWorkbench()
Expand All @@ -22,8 +43,8 @@ export const getDVCActivityBarIcon = async (): Promise<ViewControl> => {
return activityBar.getViewControl('DVC') as Promise<ViewControl>
}

export const waitForViewContainerToLoad = async () => {
const initialProgressBars = await $$('.monaco-progress-container')
export const waitForViewContainerToLoad = async (): Promise<void> => {
const initialProgressBars = await findProgressBars()
await browser.waitUntil(async () => {
const dvcIcon = await getDVCActivityBarIcon()
if (!dvcIcon) {
Expand All @@ -35,28 +56,42 @@ export const waitForViewContainerToLoad = async () => {
return !!view
})

return browser.waitUntil(async () => {
await browser.waitUntil(async () => {
const numberOfProgressBarsInContainer = 7
const currentProgressBars = await $$('.monaco-progress-container')
const currentProgressBars = await findProgressBars()

if (
return !(
currentProgressBars.length <
initialProgressBars.length + numberOfProgressBarsInContainer
) {
return false
}
)
})

await waitForDvcToFinish()

for (const progress of currentProgressBars) {
if ((await progress.getAttribute('aria-hidden')) !== 'true') {
const workbench = await browser.getWorkbench()
await workbench.executeCommand('DVC: Pull')
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[F] In the CI we need to pull all of the DVC tracked data. This was a headache to get working.


await browser.waitUntil(
async () => {
if (await dvcIsWorking()) {
return false
}
}

return true
})
const currentProgressBars = await findProgressBars()

for (const progress of currentProgressBars) {
if (await progress.isDisplayed()) {
return false
}
}

return true
},
{ timeout: 180000 }
)
}

export const closeAllEditors = async () => {
export const closeAllEditors = async (): Promise<void> => {
const workbench = await browser.getWorkbench()
const editorView = workbench.getEditorView()
return editorView.closeAllEditors()
Expand Down
24 changes: 24 additions & 0 deletions extension/src/test/e2e/wdio.conf.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,30 @@
import { join, resolve } from 'path'
import { mkdirp } from 'fs-extra'
import { Options } from '@wdio/types'
import { getVenvBinPath } from '../../python/path'
import { Logger } from '../../common/logger'

const screenshotDir = join(__dirname, 'screenshots')

export const config: Options.Testrunner = {
after: async function () {
await browser.switchToFrame(null)
await browser.switchToFrame(null)
},
afterTest: async (test, __, { passed }) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[F] This is close to what is provided in the example tests for the service. If I get time I will extend the way that we do timeouts to also take screenshots.

if (passed) {
return
}

Logger.log('Capturing screenshot for debugging')

await browser.saveScreenshot(
join(screenshotDir, `${test.parent} - ${test.title}.png`)
)
},
baseUrl: 'http://localhost',
before: async function () {
mkdirp(screenshotDir)
await browser.setWindowSize(1600, 1200)
},
capabilities: [
Expand All @@ -17,6 +34,13 @@ export const config: Options.Testrunner = {
// @ts-expect-error these caps are not typed in WebdriverIO
'wdio:vscodeOptions': {
extensionPath: resolve(__dirname, '..', '..', '..'),
userSettings: {
'dvc.pythonPath': getVenvBinPath(
resolve(__dirname, '..', '..', '..', '..', 'demo'),
'.env',
'python'
)
},
verboseLogging: false,
workspacePath: resolve(__dirname, '..', '..', '..', '..', 'demo')
}
Expand Down