test(android): add tests for Gradle utility functions (#687)

This commit is contained in:
Tommy Nguyen 2022-01-05 10:28:31 +01:00 коммит произвёл GitHub
Родитель 44c9118f76
Коммит 2e42594099
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
4 изменённых файлов: 351 добавлений и 1 удалений

1
.github/actions/setup-toolchain/action.yml поставляемый
Просмотреть файл

@ -11,7 +11,6 @@ runs:
with:
node-version: 14
- name: Set up JDK
if: ${{ inputs.platform == 'android' }}
uses: actions/setup-java@v2.5.0
with:
distribution: temurin

1
.gitignore поставляемый
Просмотреть файл

@ -2,6 +2,7 @@
*.tgz
*.xcworkspace/
.DS_Store
.android-test-*
.gradle/
.idea/
.vs/

Просмотреть файл

@ -0,0 +1,114 @@
// @ts-check
// istanbul ignore file
const { spawnSync } = require("child_process");
const fs = require("fs/promises");
const os = require("os");
const path = require("path");
const { version: targetVersion } = require("react-native/package.json");
const { gatherConfig, writeAllFiles } = require("../../scripts/configure");
/**
* Joins the strings if an array is passed, otherwise returns the string.
* @param {string | string[]} strings
* @returns
*/
function joinStrings(strings, separator = "") {
return Array.isArray(strings) ? strings.join(separator) : strings;
}
/**
* Returns project path given name.
* @param {string} name
*/
function projectPath(name) {
return `.android-test-${name}`;
}
/**
* Initializes a React Native project.
* @param {string} name
* @param {import("../../scripts/configure").ConfigureParams["platforms"]} platforms
* @param {Record<string, string | string[]>=} setupFiles
*/
async function makeProject(name, platforms, setupFiles = {}) {
const packagePath = projectPath(name);
const { files } = gatherConfig({
name,
packagePath,
testAppPath: path.resolve(__dirname, "..", ".."),
targetVersion,
platforms,
flatten: true,
force: true,
init: true,
});
await writeAllFiles(files, packagePath);
try {
await fs.symlink(
path.resolve(__dirname, "..", "..", "example", "node_modules"),
path.join(packagePath, "node_modules"),
"dir"
);
} catch (e) {
// @ts-ignore
if (e.code !== "EEXIST") {
throw e;
}
}
await Promise.all(
Object.entries(setupFiles).map(([filename, content]) => {
const p = path.join(packagePath, filename);
return fs
.mkdir(path.dirname(p), { recursive: true })
.then(() => fs.writeFile(p, joinStrings(content, "\n")));
})
);
return packagePath;
}
/**
* Removes specified project.
* @param {string} name
*/
function removeProject(name) {
fs.rm(projectPath(name), {
maxRetries: 3,
recursive: true,
});
}
/**
* Runs Gradle in specified directory.
* @param {string} cwd
* @param {...string} args arguments
* @returns
*/
function runGradle(cwd, ...args) {
const gradlew = os.platform() === "win32" ? "gradlew.bat" : "./gradlew";
return spawnSync(gradlew, args, { cwd, encoding: "utf-8" });
}
/**
* Initializes a new React Native project and runs Gradle.
* @param {string} name
* @param {import("../../scripts/configure").ConfigureParams["platforms"]} platforms
* @param {Record<string, string | string[]>=} setupFiles
*/
async function runGradleWithProject(name, platforms, setupFiles = {}) {
const projectPath = await makeProject(name, platforms, setupFiles);
const result = runGradle(projectPath);
const stdout = joinStrings(result.stdout);
if (result.stderr) {
console.log(stdout);
console.error(joinStrings(result.stderr));
}
return { ...result, stdout };
}
exports.removeProject = removeProject;
exports.runGradleWithProject = runGradleWithProject;

Просмотреть файл

@ -0,0 +1,236 @@
// @ts-check
"use strict";
describe("test-app-util", () => {
const { removeProject, runGradleWithProject } = require("./gradle");
const buildGradle = [
"buildscript {",
' def androidTestAppDir = "node_modules/react-native-test-app/android"',
' apply(from: "${androidTestAppDir}/dependencies.gradle")',
' apply(from: "${androidTestAppDir}/test-app-util.gradle")',
"",
" repositories {",
" mavenCentral()",
" google()",
" }",
"",
" dependencies {",
' classpath "com.android.tools.build:gradle:$androidPluginVersion"',
' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"',
" }",
"}",
"",
];
const defaultTestProject = "TestAppUtilTest";
/**
* Runs Gradle in test project.
* @param {Record<string, string | string[]>=} setupFiles
*/
function runGradle(setupFiles) {
return runGradleWithProject(defaultTestProject, ["android"], setupFiles);
}
/**
* Returns version number.
* @param {string} version
* @returns
*/
function toVersionNumber(version) {
const [major, minor, patch] = version.split(".");
return Number(major) * 10000 + Number(minor) * 100 + Number(patch);
}
afterAll(() => {
removeProject(defaultTestProject);
});
test("getAppName() returns `name` if `displayName` is omitted", async () => {
const { status, stdout } = await runGradle({
"app.json": JSON.stringify({
name: "AppName",
resources: ["dist/res", "dist/main.android.jsbundle"],
}),
"build.gradle": [
...buildGradle,
'println("getAppName() = " + ext.getAppName())',
],
});
expect(status).toBe(0);
expect(stdout).toContain("getAppName() = AppName");
});
test("getAppName() returns `displayName` if set", async () => {
const { status, stdout } = await runGradle({
"app.json": JSON.stringify({
name: "AppName",
displayName: "AppDisplayName",
resources: ["dist/res", "dist/main.android.jsbundle"],
}),
"build.gradle": [
...buildGradle,
'println("getAppName() = " + ext.getAppName())',
],
});
expect(status).toBe(0);
expect(stdout).toContain("getAppName() = AppDisplayName");
});
test("getApplicationId() returns default id", async () => {
const { status, stdout } = await runGradle({
"app.json": JSON.stringify({
name: "AppName",
displayName: "AppDisplayName",
resources: ["dist/res", "dist/main.android.jsbundle"],
}),
"build.gradle": [
...buildGradle,
'println("getApplicationId() = " + ext.getApplicationId())',
],
});
expect(status).toBe(0);
expect(stdout).toContain("getApplicationId() = com.microsoft.reacttestapp");
});
test("getApplicationId() returns package name", async () => {
const { status, stdout } = await runGradle({
"app.json": JSON.stringify({
name: "AppName",
displayName: "AppDisplayName",
android: {
package: "com.contoso.application.id",
},
resources: ["dist/res", "dist/main.android.jsbundle"],
}),
"build.gradle": [
...buildGradle,
'println("getApplicationId() = " + ext.getApplicationId())',
],
});
expect(status).toBe(0);
expect(stdout).toContain("getApplicationId() = com.contoso.application.id");
});
test("getFlipperRecommendedVersion() returns `null` if unsupported", async () => {
const { status, stdout } = await runGradle({
"build.gradle": [
...buildGradle,
'println("getFlipperRecommendedVersion() = " + ext.getFlipperRecommendedVersion(file("${rootDir}/no-flipper")))',
],
"no-flipper/node_modules/react-native/template/android/gradle.properties":
"",
});
expect(status).toBe(0);
expect(stdout).toContain("getFlipperRecommendedVersion() = null");
});
test("getFlipperRecommendedVersion() returns version number if supported", async () => {
const { status, stdout } = await runGradle({
"build.gradle": [
...buildGradle,
'println("getFlipperRecommendedVersion() = " + ext.getFlipperRecommendedVersion(rootDir))',
],
});
expect(status).toBe(0);
expect(stdout).toMatch(/getFlipperRecommendedVersion\(\) = \d+\.\d+\.\d+/);
});
test("getFlipperVersion() returns `null` if unsupported", async () => {
const { status, stdout } = await runGradle({
"build.gradle": [
...buildGradle,
'println("getFlipperVersion() = " + ext.getFlipperVersion(file("${rootDir}/no-flipper")))',
],
"no-flipper/node_modules/react-native/template/android/gradle.properties":
"",
});
expect(status).toBe(0);
expect(stdout).toContain("getFlipperVersion() = null");
});
test("getFlipperVersion() returns recommended version if unset", async () => {
const { status, stdout } = await runGradle({
"build.gradle": [
...buildGradle,
'println("getFlipperVersion() = " + ext.getFlipperVersion(rootDir))',
],
});
expect(status).toBe(0);
expect(stdout).toMatch(/getFlipperVersion\(\) = \d+\.\d+\.\d+/);
});
test("getFlipperVersion() returns user set version", async () => {
const { status, stdout } = await runGradle({
"build.gradle": [
...buildGradle,
'println("getFlipperVersion() = " + ext.getFlipperVersion(rootDir))',
],
"gradle.properties": [
"android.useAndroidX=true",
"android.enableJetifier=true",
"FLIPPER_VERSION=0.0.0-test",
],
});
expect(status).toBe(0);
expect(stdout).toContain("getFlipperVersion() = 0.0.0-test");
});
test("getFlipperVersion() returns null if disabled", async () => {
const { status, stdout } = await runGradle({
"build.gradle": [
...buildGradle,
'println("getFlipperVersion() = " + ext.getFlipperVersion(rootDir))',
],
"gradle.properties": [
"android.useAndroidX=true",
"android.enableJetifier=true",
"FLIPPER_VERSION=false",
],
});
expect(status).toBe(0);
expect(stdout).toContain("getFlipperVersion() = null");
});
test("getReactNativeVersionNumber() returns react-native version as a number", async () => {
const { status, stdout } = await runGradle({
"build.gradle": [
...buildGradle,
'println("getReactNativeVersionNumber() = " + ext.getReactNativeVersionNumber(rootDir))',
],
});
expect(status).toBe(0);
const { version } = require("react-native/package.json");
expect(stdout).toContain(
`getReactNativeVersionNumber() = ${toVersionNumber(version)}`
);
});
test("getReactNativeVersionNumber() handles pre-release identifiers", async () => {
const { status, stdout } = await runGradle({
"build.gradle": [
...buildGradle,
'println("getReactNativeVersionNumber() = " + ext.getReactNativeVersionNumber(file("${rootDir}/pre-release-version")))',
],
"pre-release-version/node_modules/react-native/package.json":
JSON.stringify({ name: "react-native", version: "1.2.3-053c2b4be" }),
});
expect(status).toBe(0);
expect(stdout).toContain(`getReactNativeVersionNumber() = 10203`);
});
});