-
Notifications
You must be signed in to change notification settings - Fork 24.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into @@jpiasecki/display-contents-poc
- Loading branch information
Showing
493 changed files
with
11,152 additions
and
8,276 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -90,4 +90,4 @@ untyped-import | |
untyped-type-import | ||
|
||
[version] | ||
^0.246.0 | ||
^0.247.1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,6 +17,15 @@ inputs: | |
required: false | ||
default: 'true' | ||
description: whether this action has to install java 17 or not | ||
flavor: | ||
required: true | ||
description: the flavor we want to run - either debug or release | ||
default: release | ||
working-directory: | ||
required: false | ||
default: "." | ||
description: The directory from which metro should be started | ||
|
||
runs: | ||
using: composite | ||
steps: | ||
|
@@ -25,7 +34,7 @@ runs: | |
run: export MAESTRO_VERSION=1.36.0; curl -Ls "https://get.maestro.mobile.dev" | bash | ||
- name: Set up JDK 17 | ||
if: ${{ inputs.install-java == 'true' }} | ||
uses: actions/setup-java@v2 | ||
uses: actions/setup-java@v4 | ||
with: | ||
java-version: '17' | ||
distribution: 'zulu' | ||
|
@@ -38,33 +47,38 @@ runs: | |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules | ||
sudo udevadm control --reload-rules | ||
sudo udevadm trigger --name-match=kvm | ||
- name: Build Codegen | ||
shell: bash | ||
if: ${{ inputs.flavor == 'debug' }} | ||
run: ./packages/react-native-codegen/scripts/oss/build.sh | ||
- name: Run e2e tests | ||
uses: reactivecircus/android-emulator-runner@v2 | ||
with: | ||
api-level: 24 | ||
arch: x86 | ||
script: | | ||
echo "Install APK from ${{ inputs.app-path }}" | ||
adb install "${{ inputs.app-path }}" | ||
echo "Start recording to /sdcard/screen.mp4" | ||
adb shell screenrecord /sdcard/screen.mp4 | ||
echo "Start testing ${{ inputs.maestro-flow }}" | ||
$HOME/.maestro/bin/maestro test ${{ inputs.maestro-flow }} --format junit -e APP_ID=${{ inputs.app-id }} --debug-output /tmp/MaestroLogs | ||
echo "Stop recording. Saving to screen.mp4" | ||
adb pull /sdcard/screen.mp4 | ||
ram-size: '4096M' | ||
disk-size: '10G' | ||
disable-animations: false | ||
avd-name: e2e_emulator | ||
script: node .github/workflow-scripts/maestro-android.js ${{ inputs.app-path }} ${{ inputs.app-id }} ${{ inputs.maestro-flow }} ${{ inputs.flavor }} ${{ inputs.working-directory }} | ||
- name: Normalize APP_ID | ||
id: normalize-app-id | ||
shell: bash | ||
if: always() | ||
run: | | ||
NORM_APP_ID=$(echo "${{ inputs.app-id }}" | tr '.' '-') | ||
echo "app-id=$NORM_APP_ID" >> $GITHUB_OUTPUT | ||
- name: Store tests result | ||
uses: actions/upload-artifact@v3 | ||
if: always() | ||
with: | ||
name: e2e_android_${{ inputs.app-id }}_report_${{ inputs.jsengine }} | ||
name: e2e_android_${{ steps.normalize-app-id.outputs.app-id }}_report_${{ inputs.jsengine }}_${{ inputs.flavor }} | ||
path: | | ||
report.xml | ||
screen.mp4 | ||
- name: Store Logs | ||
if: failure() && steps.run-tests.outcome == 'failure' | ||
uses: actions/[email protected] | ||
with: | ||
name: maestro-logs-android-${{ inputs.app-id }}-${{ inputs.jsengine }} | ||
name: maestro-logs-android-${{ steps.normalize-app-id.outputs.app-id }}-${{ inputs.jsengine }}-${{ inputs.flavor }} | ||
path: /tmp/MaestroLogs |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,6 +13,15 @@ inputs: | |
maestro-flow: | ||
required: true | ||
description: the folder that contains the maestro tests | ||
flavor: | ||
required: true | ||
description: Whether we are building for Debug or Release | ||
default: Release | ||
working-directory: | ||
required: false | ||
default: "." | ||
description: The directory from which metro should be started | ||
|
||
runs: | ||
using: composite | ||
steps: | ||
|
@@ -29,6 +38,12 @@ runs: | |
with: | ||
java-version: '17' | ||
distribution: 'zulu' | ||
- name: Start Metro in Debug | ||
shell: bash | ||
if: ${{ inputs.flavor == 'Debug' }} | ||
run: | | ||
cd ${{ inputs.working-directory }} | ||
yarn start & | ||
- name: Run tests | ||
id: run-tests | ||
shell: bash | ||
|
@@ -54,17 +69,24 @@ runs: | |
xcrun simctl launch $UDID ${{ inputs.app-id }} | ||
echo "Running tests with Maestro" | ||
export MAESTRO_DRIVER_STARTUP_TIMEOUT=1500000 # 25 min. CI is extremely slow | ||
export MAESTRO_DRIVER_STARTUP_TIMEOUT=1800000 # 30 min. CI is extremely slow | ||
# Add retries for flakyness | ||
MAX_ATTEMPTS=3 | ||
MAX_ATTEMPTS=5 | ||
CURR_ATTEMPT=0 | ||
RESULT=1 | ||
while [[ $CURR_ATTEMPT -lt $MAX_ATTEMPTS ]] && [[ $RESULT -ne 0 ]]; do | ||
if [[ $CURR_ATTEMPT -ne 0 ]]; then | ||
echo "Rebooting simulator for stability" | ||
xcrun simctl boot "iPhone 15 Pro" | ||
fi | ||
CURR_ATTEMPT=$((CURR_ATTEMPT+1)) | ||
echo "Attempt number $CURR_ATTEMPT" | ||
echo "Start video record using pid: video_record_${{ inputs.jsengine }}_$CURR_ATTEMPT.pid" | ||
xcrun simctl io booted recordVideo video_record_$CURR_ATTEMPT.mov & echo $! > video_record_${{ inputs.jsengine }}_$CURR_ATTEMPT.pid | ||
|
@@ -75,14 +97,17 @@ runs: | |
# Stop video | ||
kill -SIGINT $(cat video_record_${{ inputs.jsengine }}_$CURR_ATTEMPT.pid) | ||
echo "Shutting down simulator for stability" | ||
xcrun simctl shutdown "iPhone 15 Pro" | ||
done | ||
exit $RESULT | ||
- name: Store video record | ||
if: always() | ||
uses: actions/[email protected] | ||
with: | ||
name: e2e_ios_${{ inputs.app-id }}_report_${{ inputs.jsengine }} | ||
name: e2e_ios_${{ inputs.app-id }}_report_${{ inputs.jsengine }}_${{ inputs.flavor }} | ||
path: | | ||
video_record_1.mov | ||
video_record_2.mov | ||
|
@@ -92,5 +117,5 @@ runs: | |
if: failure() && steps.run-tests.outcome == 'failure' | ||
uses: actions/[email protected] | ||
with: | ||
name: maestro-logs-${{ inputs.app-id }}-${{ inputs.jsengine }} | ||
name: maestro-logs-${{ inputs.app-id }}-${{ inputs.jsengine }}-${{ inputs.flavor }} | ||
path: /tmp/MaestroLogs |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
158 changes: 158 additions & 0 deletions
158
.github/workflow-scripts/__tests__/publishTemplate-test.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
/** | ||
* Copyright (c) Meta Platforms, Inc. and affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
* | ||
* @format | ||
*/ | ||
|
||
const { | ||
publishTemplate, | ||
verifyPublishedTemplate, | ||
} = require('../publishTemplate'); | ||
|
||
const mockRun = jest.fn(); | ||
const mockSleep = jest.fn(); | ||
const mockGetNpmPackageInfo = jest.fn(); | ||
const silence = () => {}; | ||
|
||
jest.mock('../utils.js', () => ({ | ||
log: silence, | ||
run: mockRun, | ||
sleep: mockSleep, | ||
getNpmPackageInfo: mockGetNpmPackageInfo, | ||
})); | ||
|
||
const getMockGithub = () => ({ | ||
rest: { | ||
actions: { | ||
createWorkflowDispatch: jest.fn(), | ||
}, | ||
}, | ||
}); | ||
|
||
describe('#publishTemplate', () => { | ||
beforeEach(jest.clearAllMocks); | ||
|
||
it('checks commits for magic #publish-package-to-npm&latest string and sets latest', async () => { | ||
mockRun.mockReturnValueOnce(` | ||
The commit message | ||
#publish-packages-to-npm&latest`); | ||
|
||
const github = getMockGithub(); | ||
await publishTemplate(github, '0.76.0', true); | ||
expect(github.rest.actions.createWorkflowDispatch).toHaveBeenCalledWith({ | ||
owner: 'react-native-community', | ||
repo: 'template', | ||
workflow_id: 'release.yml', | ||
ref: '0.76-stable', | ||
inputs: { | ||
dry_run: true, | ||
is_latest_on_npm: true, | ||
version: '0.76.0', | ||
}, | ||
}); | ||
}); | ||
|
||
it('pubished as is_latest_on_npm = false if missing magic string', async () => { | ||
mockRun.mockReturnValueOnce(` | ||
The commit message without magic | ||
`); | ||
|
||
const github = getMockGithub(); | ||
await publishTemplate(github, '0.76.0', false); | ||
expect(github.rest.actions.createWorkflowDispatch).toHaveBeenCalledWith({ | ||
owner: 'react-native-community', | ||
repo: 'template', | ||
workflow_id: 'release.yml', | ||
ref: '0.76-stable', | ||
inputs: { | ||
dry_run: false, | ||
is_latest_on_npm: false, | ||
version: '0.76.0', | ||
}, | ||
}); | ||
}); | ||
}); | ||
|
||
describe('#verifyPublishedTemplate', () => { | ||
beforeEach(jest.clearAllMocks); | ||
|
||
it("waits on npm updating for version and not 'latest'", async () => { | ||
const NOT_LATEST = false; | ||
mockGetNpmPackageInfo | ||
// template@<version> | ||
.mockReturnValueOnce(Promise.reject('mock http/404')) | ||
.mockReturnValueOnce(Promise.resolve()); | ||
mockSleep.mockReturnValueOnce(Promise.resolve()).mockImplementation(() => { | ||
throw new Error('Should not be called again!'); | ||
}); | ||
|
||
const version = '0.77.0'; | ||
await verifyPublishedTemplate(version, NOT_LATEST); | ||
|
||
expect(mockGetNpmPackageInfo).toHaveBeenLastCalledWith( | ||
'@react-native-community/template', | ||
version, | ||
); | ||
}); | ||
|
||
it('waits on npm updating version and latest tag', async () => { | ||
const IS_LATEST = true; | ||
const version = '0.77.0'; | ||
mockGetNpmPackageInfo | ||
// template@latest → unknown tag | ||
.mockReturnValueOnce(Promise.reject('mock http/404')) | ||
// template@latest != version → old tag | ||
.mockReturnValueOnce(Promise.resolve({version: '0.76.5'})) | ||
// template@latest == version → correct tag | ||
.mockReturnValueOnce(Promise.resolve({version})); | ||
mockSleep | ||
.mockReturnValueOnce(Promise.resolve()) | ||
.mockReturnValueOnce(Promise.resolve()) | ||
.mockImplementation(() => { | ||
throw new Error('Should not be called again!'); | ||
}); | ||
|
||
await verifyPublishedTemplate(version, IS_LATEST); | ||
|
||
expect(mockGetNpmPackageInfo).toHaveBeenCalledWith( | ||
'@react-native-community/template', | ||
'latest', | ||
); | ||
}); | ||
|
||
describe('timeouts', () => { | ||
let mockProcess; | ||
beforeEach(() => { | ||
mockProcess = jest.spyOn(process, 'exit').mockImplementation(code => { | ||
throw new Error(`process.exit(${code}) called!`); | ||
}); | ||
}); | ||
afterEach(() => mockProcess.mockRestore()); | ||
it('will timeout if npm does not update package version after a set number of retries', async () => { | ||
const RETRIES = 2; | ||
mockGetNpmPackageInfo.mockReturnValue(Promise.reject('mock http/404')); | ||
mockSleep.mockReturnValue(Promise.resolve()); | ||
await expect(() => | ||
verifyPublishedTemplate('0.77.0', true, RETRIES), | ||
).rejects.toThrowError('process.exit(1) called!'); | ||
expect(mockGetNpmPackageInfo).toHaveBeenCalledTimes(RETRIES); | ||
}); | ||
|
||
it('will timeout if npm does not update latest tag after a set number of retries', async () => { | ||
const RETRIES = 7; | ||
const IS_LATEST = true; | ||
mockGetNpmPackageInfo.mockReturnValue( | ||
Promise.resolve({version: '0.76.5'}), | ||
); | ||
mockSleep.mockReturnValue(Promise.resolve()); | ||
await expect(async () => { | ||
await verifyPublishedTemplate('0.77.0', IS_LATEST, RETRIES); | ||
}).rejects.toThrowError('process.exit(1) called!'); | ||
expect(mockGetNpmPackageInfo).toHaveBeenCalledTimes(RETRIES); | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.