Skip to content

Commit

Permalink
wip: crude e2e
Browse files Browse the repository at this point in the history
  • Loading branch information
aethernet committed Apr 27, 2024
1 parent 6a648e9 commit e1d9f97
Show file tree
Hide file tree
Showing 13 changed files with 202 additions and 22 deletions.
58 changes: 57 additions & 1 deletion .github/actions/test/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,56 @@ runs:
with:
python-version: '3.11'

- name: Setup Virtual Drive on MacOS
if: runner.os == 'macOS'
shell: bash
run: |
hdiutil create -size 4096m -layout NONE -o virtual_test_disk.dmg
virtual_path=$(hdiutil attach -nomount virtual_test_disk.dmg)
echo "TARGET_DRIVE=${virtual_path}" >> $GITHUB_ENV
echo "ETCHER_INCLUDE_VIRTUAL_DRIVES=1" >> $GITHUB_ENV
- name: Setup Virtual Drive on Linux
if: runner.os == 'Linux'
shell: bash
run: |
dd if=/dev/zero of=virtual_test_disk.img bs=1M count=4096
virtual_path=$(sudo losetup -f --show virtual_test_disk.img)
echo "TARGET_DRIVE=${virtual_path}" >> $GITHUB_ENV
- name: Setup Virtual Drive on Windows
if: runner.os == 'Windows'
shell: pwsh
run: |
fsutil file createnew virtual_test_disk.img 4294967296
# Use DiskPart to attach and list volumes
$diskpartScript = @"
SELECT VDISK FILE=virtual_test_disk.img
ATTACH VDISK
LIST VOLUME
"@
diskpart /s $diskpartScript | Out-File -FilePath diskpart_output.txt -Encoding UTF8
# Extract the volume information from the DiskPart output
$diskpartOutput = Get-Content -Path diskpart_output.txt
$driveLine = $diskpartOutput | Select-String -Pattern "virtual_test_disk.img"
# Extract drive letter
$driveLetter = $null
if ($driveLine) {
$tokens = $driveLine -split "\s+"
$driveLetter = $tokens[2]
}

echo "TARGET_DRIVE=!drive_letter!:\\" >> %GITHUB_ENV%

- name: Test release
shell: bash
run: |
# Build and Test release
## FIXME: causes issues with `xxhash` which tries to load a debug build which doens't exist and cannot be compiled
# if [[ '${{ inputs.VERBOSE }}' =~ on|On|Yes|yes|true|True ]]; then
# export DEBUG='electron-forge:*,sidecar'
Expand All @@ -57,8 +104,17 @@ runs:
npm ci
npm run lint
npm run package
npm run wdio # test stage, note that it requires the package to be done first
# tests; note that they required `package` to run before
npm run wdio
# e2e suite requires administrative privileges
if [[ '${{ runner.os }}' == 'Windows' ]]; then
npm run wdio-e2e
else
sudo TARGET_DRIVE=${{ env.TARGET_DRIVE }} ETCHER_INCLUDE_VIRTUAL_DRIVES=1 npm run wdio-e2e
fi
env:
# https://www.electronjs.org/docs/latest/api/environment-variables
ELECTRON_NO_ATTACH_CONSOLE: 'true'
Expand Down
8 changes: 7 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -120,4 +120,10 @@ secrets/WINDOWS_SIGNING.pfx

#local development
.yalc
yalc.lock
yalc.lock

# Test assets
virtual_test_disk.dmg
virtual_test_disk.img
virtual_test_disk.vhd
screenshots/
1 change: 1 addition & 0 deletions lib/gui/app/components/drive-selector/drive-selector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,7 @@ export class DriveSelector extends React.Component<
primary: !showWarnings,
warning: showWarnings,
disabled: !hasAvailableDrives(),
'data-testid': 'validate-target-button',
}}
{...props}
>
Expand Down
2 changes: 1 addition & 1 deletion lib/gui/app/components/flash-results/flash-results.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ export function FlashResults({
/>
<Txt>{middleEllipsis(image, 24)}</Txt>
</Flex>
<Txt fontSize={24} color="#fff" mb="17px">
<Txt data-testid="flash-results" fontSize={24} color="#fff" mb="17px">
{allFailed
? i18next.t('flash.flashFailed')
: i18next.t('flash.flashCompleted')}
Expand Down
5 changes: 4 additions & 1 deletion lib/gui/app/components/progress-button/progress-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,9 @@ export class ProgressButton extends React.PureComponent<ProgressButtonProps> {
}}
>
<Flex>
<Txt color="#fff">{status}&nbsp;</Txt>
<Txt data-testid="flash-status" color="#fff">
{status}&nbsp;
</Txt>
<Txt color={colors[type]}>{position}</Txt>
</Flex>
{type && (
Expand All @@ -125,6 +127,7 @@ export class ProgressButton extends React.PureComponent<ProgressButtonProps> {
warning={warning}
onClick={this.props.callback}
disabled={this.props.disabled}
data-testid={'flash-now-button'}
style={{
marginTop: 30,
}}
Expand Down
4 changes: 4 additions & 0 deletions lib/gui/app/components/source-selector/source-selector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ const URLSelector = ({
cancel={cancel}
primaryButtonProps={{
disabled: loading || !imageURL,
'data-testid': 'source-url-ok-button',
}}
action={loading ? <Spinner /> : i18next.t('ok')}
done={async () => {
Expand All @@ -186,6 +187,7 @@ const URLSelector = ({
</Txt>
<Input
value={imageURL}
data-testid="source-url-input"
placeholder={i18next.t('source.enterValidURL')}
type="text"
onChange={(evt: React.ChangeEvent<HTMLInputElement>) =>
Expand Down Expand Up @@ -655,6 +657,7 @@ export class SourceSelector extends React.Component<
disabled={this.state.imageSelectorOpen}
primary={this.state.defaultFlowActive}
key="Flash from file"
data-testid="flash-from-file"
flow={{
onClick: () => this.openImageSelector(),
label: i18next.t('source.fromFile'),
Expand All @@ -665,6 +668,7 @@ export class SourceSelector extends React.Component<
/>
<FlowSelector
key="Flash from URL"
data-testid="flash-from-url"
flow={{
onClick: () => this.openURLSelector(),
label: i18next.t('source.fromURL'),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ export function TargetSelectorButton(props: TargetSelectorProps) {
tabIndex={targets.length > 0 ? -1 : 2}
disabled={props.disabled}
onClick={props.openDriveSelector}
data-testid="select-target-button"
>
{i18next.t('target.selectTarget')}
</StepButton>
Expand Down
2 changes: 2 additions & 0 deletions lib/util/drive-scanner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import { geteuid, platform } from 'process';
const adapters: Adapter[] = [
new BlockDeviceAdapter({
includeSystemDrives: () => true,
includeVirtualDrives: () =>
process.env.ETCHER_INCLUDE_VIRTUAL_DRIVES === '1',
}),
];

Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@
"package": "electron-forge package",
"start": "electron-forge start",
"make": "electron-forge make",
"wdio": "xvfb-maybe wdio run ./wdio.conf.ts"
"wdio": "xvfb-maybe wdio run ./wdio.conf.ts --suite gui --suite shared",
"wdio:e2e": "xvfb-maybe wdio run ./wdio.conf.ts --suite e2e",
"wdio:all": "xvfb-maybe wdio run ./wdio.conf.ts --suite gui --suite shared --suite e2e"
},
"husky": {
"hooks": {
Expand Down
42 changes: 42 additions & 0 deletions tests/e2e/e2e-flash-from-file.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { browser } from '@wdio/globals';

describe('Electron Testing', () => {
it('should print application title', async () => {
console.log('Hello', await browser.getTitle(), 'application!');
});

it('should "flash from file"', async () => {
const flashFromFileButton = $('button[data-testid="flash-from-file"]');
await flashFromFileButton.waitForDisplayed({ timeout: 10000 });
// const isDisplayed = await flashFromFileButton.isDisplayed();
await flashFromFileButton.click();

const selectTargetButton = $('button[data-testid="select-target-button"]');
await selectTargetButton.waitForClickable({ timeout: 30000 });
await selectTargetButton.click();

// TODO: Select target using ENV variable for the drive
const targetVirtualDrive = $('=/dev/disk8');
await targetVirtualDrive.waitForDisplayed({ timeout: 10000 });
await targetVirtualDrive.click();

const validateTargetButton = $(
'button[data-testid="validate-target-button"]',
);
await validateTargetButton.waitForClickable({ timeout: 10000 });
await validateTargetButton.click();

const flashNowButton = $('button[data-testid="flash-now-button"]');
await flashNowButton.waitForClickable({ timeout: 10000 });
await flashNowButton.click();

// FIXME: not able to find the flashResults :(
const flashResults = $('span[data-testid="flash-results"]');
await flashResults.waitForDisplayed({ timeout: 20000 });

expect(flashResults.getText()).toBe('Flash Completed!');

// we're good;
// now we should check the content of the image but we can do that outside wdio
});
});
61 changes: 61 additions & 0 deletions tests/e2e/e2e-flash-from-url.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { browser } from '@wdio/globals';

describe('Electron Testing', () => {
it('should print application title', async () => {
console.log('Hello', await browser.getTitle(), 'application!');
});

it('should "select an url source"', async () => {
const flashFromUrlButton = $('button[data-testid="flash-from-url"]');
await flashFromUrlButton.waitForDisplayed({ timeout: 10000 });
// const isDisplayed = await flashFromFileButton.isDisplayed();
await flashFromUrlButton.click();

const enterValidUrlInput = $('input[data-testid="source-url-input"]');
await enterValidUrlInput.waitForDisplayed({ timeout: 10000 });

// TODO: use an env variable for the URL
await enterValidUrlInput.setValue(
'https://api.balena-cloud.com/download?deviceType=raspberrypi4-64&version=5.2.8&fileType=.zip&developmentMode=true',
);

const sourceUrlOkButton = $('button[data-testid="source-url-ok-button"]');
await sourceUrlOkButton.waitForDisplayed({ timeout: 10000 });
await sourceUrlOkButton.click();
});

it('should "select a virtual target"', async () => {
const selectTargetButton = $('button[data-testid="select-target-button"]');
await selectTargetButton.waitForClickable({ timeout: 30000 });
await selectTargetButton.click();

// target drive is set in the github custom test action
// if you run the test locally, pass the varibale
const targetVirtualDrive = $(`=${process.env.TARGET_DRIVE}`);
await targetVirtualDrive.waitForDisplayed({ timeout: 10000 });
await targetVirtualDrive.click();

const validateTargetButton = $(
'button[data-testid="validate-target-button"]',
);
await validateTargetButton.waitForClickable({ timeout: 10000 });
await validateTargetButton.click();
});

it('should "start flashing"', async () => {
const flashNowButton = $('button[data-testid="flash-now-button"]');
await flashNowButton.waitForClickable({ timeout: 10000 });
await flashNowButton.click();
});

it('should get the "Flash Completed" screen', async () => {
const flashResults = $('[data-testid="flash-results"]');
await flashResults.waitForDisplayed({ timeout: 180000 });

const flashResultsText = await flashResults.getText();
expect(flashResultsText).toBe('Flash Completed!');

// we're good;
// now we should check the content of the image but we can do that outside wdio
});
});
7 changes: 0 additions & 7 deletions tests/test.e2e.ts

This file was deleted.

29 changes: 19 additions & 10 deletions wdio.conf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,25 @@ export const config: Options.Testrunner = {
// Patterns to exclude.
// FIXME: Remove the following exclusions once the tests are ported to WDIO
exclude: [
'tests/gui/modules/image-writer.spec.ts',
'tests/gui/os/window-progress.spec.ts',
'tests/gui/models/available-drives.spec.ts',
'tests/gui/models/flash-state.spec.ts',
'tests/gui/models/selection-state.spec.ts',
'tests/gui/models/settings.spec.ts',
'tests/shared/drive-constraints.spec.ts',
'tests/shared/messages.spec.ts',
'tests/gui/modules/progress-status.spec.ts',
'./tests/gui/modules/image-writer.spec.ts',
'./tests/gui/os/window-progress.spec.ts',
'./tests/gui/models/available-drives.spec.ts',
'./tests/gui/models/flash-state.spec.ts',
'./tests/gui/models/selection-state.spec.ts',
'./tests/gui/models/settings.spec.ts',
'./tests/shared/drive-constraints.spec.ts',
'./tests/shared/messages.spec.ts',
'./tests/gui/modules/progress-status.spec.ts',
],

suites: {
'gui': ['./tests/gui/**/*.spec.ts'],
'shared': ['./tests/shared/**/*.spec.ts'],
'e2e': [
// 'tests/e2e/e2e-flash-from-file.spec.ts',
'./tests/e2e/e2e-flash-from-url.spec.ts',
],
},
//
// ============
// Capabilities
Expand Down Expand Up @@ -85,7 +94,7 @@ export const config: Options.Testrunner = {
// Define all options that are relevant for the WebdriverIO instance here
//
// Level of logging verbosity: trace | debug | info | warn | error | silent
logLevel: 'info',
logLevel: 'warn',
//
// Set specific log levels per logger
// loggers:
Expand Down

0 comments on commit e1d9f97

Please sign in to comment.