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

WIP: testing the possibility to build e2e within GH Actions #4213

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
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
Loading