Skip to content

Commit

Permalink
Merge branch 'main' into @@jpiasecki/display-contents-poc
Browse files Browse the repository at this point in the history
  • Loading branch information
j-piasecki committed Oct 7, 2024
2 parents 2217298 + cc6d1eb commit 1bdc2a6
Show file tree
Hide file tree
Showing 493 changed files with 11,152 additions and 8,276 deletions.
2 changes: 1 addition & 1 deletion .flowconfig
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,4 @@ untyped-import
untyped-type-import

[version]
^0.246.0
^0.247.1
44 changes: 29 additions & 15 deletions .github/actions/maestro-android/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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'
Expand All @@ -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
33 changes: 29 additions & 4 deletions .github/actions/maestro-ios/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
2 changes: 1 addition & 1 deletion .github/actions/test-ios-rntester/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ runs:
set -o pipefail && xcodebuild \
-scheme "RNTester" \
-workspace packages/rn-tester/RNTesterPods.xcworkspace \
-configuration "Release" \
-configuration "${{ inputs.flavor }}" \
-sdk "iphonesimulator" \
-destination "generic/platform=iOS Simulator" \
-derivedDataPath "/tmp/RNTesterBuild" | xcbeautify
Expand Down
158 changes: 158 additions & 0 deletions .github/workflow-scripts/__tests__/publishTemplate-test.js
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);
});
});
});
Loading

0 comments on commit 1bdc2a6

Please sign in to comment.