mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/49340 This tool enables checking the boundary between JavaScript and Native for backwards incompatible changes to protect against crashes. This is useful for: - Local Development - Over the Air updates on platforms that support it - Theoretically: Server Components with React Native Check out the Readme for more information Changelog: [General][Added] Open Sourcing React Native's Compatibility Check Reviewed By: panagosg7 Differential Revision: D69476742 fbshipit-source-id: 8af6039839c5475c1258fa82d9750a9320cf0751
1604 lines
52 KiB
JavaScript
1604 lines
52 KiB
JavaScript
/**
|
|
* 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.
|
|
*
|
|
* @flow
|
|
* @format
|
|
* @oncall react_native
|
|
*/
|
|
|
|
import type {SchemaDiff, TypeStore} from '../DiffResults';
|
|
|
|
import {schemaDiffExporter} from '../DiffResults.js';
|
|
import {
|
|
addedEnumMessage,
|
|
addedPropertiesMessage,
|
|
addedUnionMessage,
|
|
buildSchemaDiff,
|
|
hasUpdatesTypes,
|
|
removedEnumMessage,
|
|
removedPropertiesMessage,
|
|
removedUnionMessage,
|
|
summarizeDiffSet,
|
|
tooOptionalPropertiesMessage,
|
|
typeNullableChangeMessage,
|
|
} from '../VersionDiffing.js';
|
|
import {getTestSchema} from './utilities/getTestSchema.js';
|
|
|
|
const schemaBeforeAfterTypes = makeRN(
|
|
'native-module-before-after-types/NativeModuleBeforeAfterTypes',
|
|
);
|
|
|
|
const schemaBeforeAfterTypesTypesRemoved = makeRN(
|
|
'native-module-before-after-types-removed/NativeModuleBeforeAfterTypes',
|
|
);
|
|
|
|
const schemaWithRN = makeRN('native-module/NativeModule');
|
|
const schemaWithRNChanged = makeRN('native-module-changed/NativeModule');
|
|
|
|
const schemaGetConstants = makeRN('native-module-get-constants/NativeModule');
|
|
|
|
const schemaGetConstantsAddedRequiredConstant = makeRN(
|
|
'native-module-get-constants-added-required-constant/NativeModule',
|
|
);
|
|
|
|
const schemaGetConstantsAddedOptionalConstant = makeRN(
|
|
'native-module-get-constants-added-optional-constant/NativeModule',
|
|
);
|
|
|
|
const schemaGetConstantsReadOnly = makeRN(
|
|
'native-module-get-constants-readonly/NativeModule',
|
|
);
|
|
|
|
const schemaGetConstantsAddedRequiredConstantReadOnly = makeRN(
|
|
'native-module-get-constants-added-required-constant-readonly/NativeModule',
|
|
);
|
|
|
|
const schemaGetConstantsAddedOptionalConstantReadOnly = makeRN(
|
|
'native-module-get-constants-added-optional-constant-readonly/NativeModule',
|
|
);
|
|
|
|
const schemaBeforeAfterTypesTypeChanged = makeRN(
|
|
'native-module-before-after-types-type-changed/NativeModuleBeforeAfterTypes',
|
|
);
|
|
|
|
function makeRN(name: string) {
|
|
return getTestSchema(__dirname, '__fixtures__', name + '.js.flow');
|
|
}
|
|
|
|
const schemaWithRnNestedObject = makeRN('native-module-nested/NativeModule');
|
|
const schemaWithRnNestedChanged = makeRN(
|
|
'native-module-nested-changed/NativeModule',
|
|
);
|
|
const schemaWithRnNestedOptions = makeRN(
|
|
'native-module-nested-optional/NativeModule',
|
|
);
|
|
const schemaWithRnNestedNullable = makeRN(
|
|
'native-module-nested-nullable/NativeModule',
|
|
);
|
|
const schemaWithEnum = makeRN('native-module-with-enum/NativeModule');
|
|
const schemaWithEnumChanges = makeRN(
|
|
'native-module-with-enum-changes/NativeModule',
|
|
);
|
|
const schemaWithEnumTypeChanges = makeRN(
|
|
'native-module-with-enum-type-changes/NativeModule',
|
|
);
|
|
const schemaWithEnumValueChanges = makeRN(
|
|
'native-module-with-enum-value-changes/NativeModule',
|
|
);
|
|
|
|
const schemaWithEnumFromNative = makeRN(
|
|
'native-module-with-enum-from-native/NativeModule',
|
|
);
|
|
const schemaWithEnumFromNativeChanges = makeRN(
|
|
'native-module-with-enum-from-native-changes/NativeModule',
|
|
);
|
|
const schemaWithEnumFromNativeTypeChanges = makeRN(
|
|
'native-module-with-enum-from-native-type-changes/NativeModule',
|
|
);
|
|
const schemaWithEnumFromNativeValueChanges = makeRN(
|
|
'native-module-with-enum-from-native-value-changes/NativeModule',
|
|
);
|
|
|
|
const schemaWithEventEmitter = makeRN(
|
|
'native-module-with-eventemitter/NativeModule',
|
|
);
|
|
const schemaWithEventEmitterChanges = makeRN(
|
|
'native-module-with-eventemitter-changes/NativeModule',
|
|
);
|
|
const schemaWithOptionalArgument = makeRN(
|
|
'native-module-with-optional-argument/NativeModule',
|
|
);
|
|
const schemaWithUnion = makeRN('native-module-with-union/NativeModule');
|
|
const schemaWithUnionChanges = makeRN(
|
|
'native-module-with-union-changes/NativeModule',
|
|
);
|
|
const schemaWithUnionFromNative = makeRN(
|
|
'native-module-with-union-from-native/NativeModule',
|
|
);
|
|
const schemaWithUnionFromNativeChanges = makeRN(
|
|
'native-module-with-union-from-native-changes/NativeModule',
|
|
);
|
|
|
|
const schemaWithRNNativeComponent = makeRN('native-component/NativeComponent');
|
|
const schemaNativeComponentWithCommand = makeRN(
|
|
'native-component-with-command/NativeComponent',
|
|
);
|
|
const schemaNativeComponentWithCommandExtraArg = makeRN(
|
|
'native-component-with-command-extra-arg/NativeComponent',
|
|
);
|
|
|
|
const schemaNativeComponentWithCommandExtraCommand = makeRN(
|
|
'native-component-with-command-extra-command/NativeComponent',
|
|
);
|
|
|
|
const schemaNativeComponentWithProps = makeRN(
|
|
'native-component-with-props/NativeComponent',
|
|
);
|
|
|
|
const schemaNativeComponentWithPropsAddedOptionalProp = makeRN(
|
|
'native-component-with-props-added-optional-prop/NativeComponent',
|
|
);
|
|
const schemaNativeComponentWithPropsAddedRequiredProp = makeRN(
|
|
'native-component-with-props-added-required-prop/NativeComponent',
|
|
);
|
|
|
|
const schemaNativeComponentWithPropsChanges = makeRN(
|
|
'native-component-with-props-changes/NativeComponent',
|
|
);
|
|
|
|
const schemaNativeComponentWithPropsDefaultChange = makeRN(
|
|
'native-component-with-props-default-change/NativeComponent',
|
|
);
|
|
|
|
const schemaNativeComponentWithPropsNestedObject = makeRN(
|
|
'native-component-with-props-nested-object/NativeComponent',
|
|
);
|
|
|
|
const schemaNativeComponentWithPropsNestedObjectAddedOptionalKey = makeRN(
|
|
'native-component-with-props-nested-object-added-optional-key/NativeComponent',
|
|
);
|
|
|
|
const schemaNativeComponentWithPropsNestedObjectAddedRequiredKey = makeRN(
|
|
'native-component-with-props-nested-object-added-required-key/NativeComponent',
|
|
);
|
|
|
|
const schemaNativeComponentWithPropsUnion = makeRN(
|
|
'native-component-with-props-union/NativeComponent',
|
|
);
|
|
|
|
const schemaNativeComponentWithPropsUnionAdded = makeRN(
|
|
'native-component-with-props-union-added/NativeComponent',
|
|
);
|
|
|
|
const schemaNativeComponentWithPropsArrayUnion = makeRN(
|
|
'native-component-with-props-array-union/NativeComponent',
|
|
);
|
|
|
|
const schemaNativeComponentWithPropsArrayUnionAdded = makeRN(
|
|
'native-component-with-props-array-union-added/NativeComponent',
|
|
);
|
|
|
|
describe('hasUpdates', () => {
|
|
it('is given empty sets', () => {
|
|
expect(
|
|
hasUpdatesTypes({
|
|
newTypes: new Set(),
|
|
deprecatedTypes: new Set(),
|
|
objectTypeChanges: new Set(),
|
|
incompatibleChanges: new Set(),
|
|
}),
|
|
).toBeFalsy();
|
|
});
|
|
const set = new Set<TypeStore>();
|
|
set.add({
|
|
typeName: 'name',
|
|
typeInformation: {
|
|
type: 'AnyTypeAnnotation',
|
|
},
|
|
filename: 'name',
|
|
});
|
|
it('is given nonempty newTypes', () => {
|
|
expect(
|
|
hasUpdatesTypes({
|
|
newTypes: set,
|
|
deprecatedTypes: new Set(),
|
|
objectTypeChanges: new Set(),
|
|
incompatibleChanges: new Set(),
|
|
}),
|
|
).toBeTruthy();
|
|
});
|
|
it('is given nonempty deprecatedTypes', () => {
|
|
expect(
|
|
hasUpdatesTypes({
|
|
newTypes: new Set(),
|
|
deprecatedTypes: set,
|
|
objectTypeChanges: new Set(),
|
|
incompatibleChanges: new Set(),
|
|
}),
|
|
).toBeTruthy();
|
|
});
|
|
});
|
|
|
|
describe('buildSchemaDiff', () => {
|
|
it('same file, no changes', () => {
|
|
expect(
|
|
buildSchemaDiff(schemaBeforeAfterTypes, schemaBeforeAfterTypes),
|
|
).toEqual(new Set());
|
|
});
|
|
it('same RN file, no changes', () => {
|
|
expect(buildSchemaDiff(schemaWithRN, schemaWithRN)).toEqual(new Set());
|
|
});
|
|
it('two RN files, with incompatible Spec changes', () => {
|
|
expect(
|
|
schemaDiffExporter(
|
|
Array.from(buildSchemaDiff(schemaWithRN, schemaWithRNChanged))[0],
|
|
),
|
|
).toEqual(
|
|
expect.objectContaining({
|
|
framework: 'ReactNative',
|
|
status: expect.objectContaining({
|
|
incompatibleSpecs: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
changeInformation: expect.objectContaining({
|
|
incompatibleChanges: expect.arrayContaining([
|
|
expect.anything(),
|
|
]),
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
);
|
|
});
|
|
it('RN file with nested object properties, no changes', () => {
|
|
expect(
|
|
buildSchemaDiff(schemaWithRnNestedObject, schemaWithRnNestedObject),
|
|
).toEqual(new Set());
|
|
});
|
|
it('RN file with nested object properties, added', () => {
|
|
expect(
|
|
schemaDiffExporter(
|
|
Array.from(
|
|
buildSchemaDiff(schemaWithRnNestedChanged, schemaWithRnNestedObject),
|
|
)[0],
|
|
),
|
|
).toEqual(
|
|
expect.objectContaining({
|
|
framework: 'ReactNative',
|
|
status: expect.objectContaining({
|
|
incompatibleSpecs: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
changeInformation: expect.objectContaining({
|
|
objectTypeChanges: expect.any(Object),
|
|
incompatibleChanges: expect.not.arrayContaining([
|
|
expect.anything(),
|
|
]),
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
);
|
|
});
|
|
it('RN file with nested object properties, removed', () => {
|
|
expect(
|
|
schemaDiffExporter(
|
|
Array.from(
|
|
buildSchemaDiff(schemaWithRnNestedObject, schemaWithRnNestedChanged),
|
|
)[0],
|
|
),
|
|
).toEqual(
|
|
expect.objectContaining({
|
|
framework: 'ReactNative',
|
|
status: expect.objectContaining({
|
|
incompatibleSpecs: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
changeInformation: expect.objectContaining({
|
|
incompatibleChanges: expect.objectContaining({
|
|
'0': expect.objectContaining({
|
|
errorInformation: expect.objectContaining({
|
|
message: removedPropertiesMessage,
|
|
}),
|
|
}),
|
|
}),
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
);
|
|
});
|
|
it('RN file with nested object properties, optional removed', () => {
|
|
expect(
|
|
schemaDiffExporter(
|
|
Array.from(
|
|
buildSchemaDiff(schemaWithRnNestedOptions, schemaWithRnNestedObject),
|
|
)[0],
|
|
),
|
|
).toEqual(
|
|
expect.objectContaining({
|
|
framework: 'ReactNative',
|
|
status: expect.objectContaining({
|
|
incompatibleSpecs: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
changeInformation: expect.objectContaining({
|
|
incompatibleChanges: expect.objectContaining({
|
|
'0': expect.objectContaining({
|
|
errorInformation: expect.objectContaining({
|
|
message: tooOptionalPropertiesMessage,
|
|
}),
|
|
}),
|
|
}),
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
);
|
|
});
|
|
it('RN file with nested object properties, nullable added', () => {
|
|
expect(
|
|
schemaDiffExporter(
|
|
Array.from(
|
|
buildSchemaDiff(
|
|
schemaWithRnNestedNullable,
|
|
schemaWithRnNestedOptions,
|
|
),
|
|
)[0],
|
|
),
|
|
).toEqual(
|
|
expect.objectContaining({
|
|
framework: 'ReactNative',
|
|
status: expect.objectContaining({
|
|
incompatibleSpecs: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
changeInformation: expect.objectContaining({
|
|
incompatibleChanges: expect.objectContaining({
|
|
'0': expect.objectContaining({
|
|
errorInformation: expect.objectContaining({
|
|
message: typeNullableChangeMessage,
|
|
}),
|
|
}),
|
|
}),
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
);
|
|
});
|
|
it('RN file with nested object properties on function, made optional', () => {
|
|
expect(
|
|
schemaDiffExporter(
|
|
Array.from(
|
|
buildSchemaDiff(schemaWithRnNestedOptions, schemaWithRnNestedChanged),
|
|
)[0],
|
|
),
|
|
).toEqual(
|
|
expect.objectContaining({
|
|
framework: 'ReactNative',
|
|
status: expect.objectContaining({
|
|
incompatibleSpecs: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
changeInformation: expect.objectContaining({
|
|
incompatibleChanges: expect.objectContaining({
|
|
'0': expect.objectContaining({
|
|
errorInformation: expect.objectContaining({
|
|
message: tooOptionalPropertiesMessage,
|
|
}),
|
|
}),
|
|
}),
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
);
|
|
});
|
|
|
|
describe('enums', () => {
|
|
describe('toNative', () => {
|
|
it('RN with enum types, same module', () => {
|
|
expect(buildSchemaDiff(schemaWithEnum, schemaWithEnum)).toEqual(
|
|
new Set(),
|
|
);
|
|
});
|
|
it('RN with enum types, and removal', () => {
|
|
expect(
|
|
schemaDiffExporter(
|
|
Array.from(
|
|
buildSchemaDiff(schemaWithEnum, schemaWithEnumChanges),
|
|
)[0],
|
|
),
|
|
).toEqual(
|
|
expect.objectContaining({
|
|
status: expect.objectContaining({
|
|
incompatibleSpecs: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
changeInformation: expect.objectContaining({
|
|
newTypes: expect.not.arrayContaining([expect.anything()]),
|
|
deprecatedTypes: expect.not.arrayContaining([
|
|
expect.anything(),
|
|
]),
|
|
incompatibleChanges: expect.not.arrayContaining([
|
|
expect.anything(),
|
|
]),
|
|
objectTypeChanges: expect.any(Object),
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
);
|
|
});
|
|
it('RN with enum types, and addition', () => {
|
|
expect(
|
|
schemaDiffExporter(
|
|
Array.from(
|
|
buildSchemaDiff(schemaWithEnumChanges, schemaWithEnum),
|
|
)[0],
|
|
),
|
|
).toEqual(
|
|
expect.objectContaining({
|
|
framework: 'ReactNative',
|
|
status: expect.objectContaining({
|
|
incompatibleSpecs: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
changeInformation: expect.objectContaining({
|
|
incompatibleChanges: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
errorCode: 'addedEnumCases',
|
|
errorInformation: expect.objectContaining({
|
|
message: addedEnumMessage,
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
);
|
|
});
|
|
it('RN with enum types, and type changes', () => {
|
|
expect(
|
|
schemaDiffExporter(
|
|
Array.from(
|
|
buildSchemaDiff(schemaWithEnum, schemaWithEnumTypeChanges),
|
|
)[0],
|
|
),
|
|
).toEqual(
|
|
expect.objectContaining({
|
|
framework: 'ReactNative',
|
|
status: expect.objectContaining({
|
|
incompatibleSpecs: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
changeInformation: expect.objectContaining({
|
|
incompatibleChanges: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
errorInformation: expect.objectContaining({
|
|
mismatchedProperties: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
fault: expect.objectContaining({
|
|
previousError: expect.objectContaining({
|
|
previousError: expect.objectContaining({
|
|
message:
|
|
'EnumDeclaration member types are not the same',
|
|
}),
|
|
}),
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
);
|
|
});
|
|
it('RN with enum types, and value changes', () => {
|
|
expect(
|
|
schemaDiffExporter(
|
|
Array.from(
|
|
buildSchemaDiff(schemaWithEnum, schemaWithEnumValueChanges),
|
|
)[0],
|
|
),
|
|
).toEqual(
|
|
expect.objectContaining({
|
|
framework: 'ReactNative',
|
|
status: expect.objectContaining({
|
|
incompatibleSpecs: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
changeInformation: expect.objectContaining({
|
|
incompatibleChanges: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
errorInformation: expect.objectContaining({
|
|
mismatchedProperties: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
fault: expect.objectContaining({
|
|
previousError: expect.objectContaining({
|
|
previousError: expect.objectContaining({
|
|
message: 'Enum types do not match',
|
|
previousError: expect.objectContaining({
|
|
message:
|
|
'Enum contained a member with a type mismatch',
|
|
mismatchedMembers: expect.arrayContaining(
|
|
[
|
|
expect.objectContaining({
|
|
member: 'B',
|
|
}),
|
|
],
|
|
),
|
|
}),
|
|
}),
|
|
}),
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('fromNative', () => {
|
|
it('RN with enum types, same module', () => {
|
|
expect(
|
|
buildSchemaDiff(schemaWithEnumFromNative, schemaWithEnumFromNative),
|
|
).toEqual(new Set());
|
|
});
|
|
it('RN with enum types, and removal', () => {
|
|
expect(
|
|
schemaDiffExporter(
|
|
Array.from(
|
|
buildSchemaDiff(
|
|
schemaWithEnumFromNative,
|
|
schemaWithEnumFromNativeChanges,
|
|
),
|
|
)[0],
|
|
),
|
|
).toEqual(
|
|
expect.objectContaining({
|
|
framework: 'ReactNative',
|
|
status: expect.objectContaining({
|
|
incompatibleSpecs: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
changeInformation: expect.objectContaining({
|
|
incompatibleChanges: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
errorCode: 'removedEnumCases',
|
|
errorInformation: expect.objectContaining({
|
|
message: removedEnumMessage,
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
);
|
|
});
|
|
it('RN with enum types, and addition', () => {
|
|
expect(
|
|
schemaDiffExporter(
|
|
Array.from(
|
|
buildSchemaDiff(
|
|
schemaWithEnumFromNativeChanges,
|
|
schemaWithEnumFromNative,
|
|
),
|
|
)[0],
|
|
),
|
|
).toEqual(
|
|
expect.objectContaining({
|
|
status: expect.objectContaining({
|
|
incompatibleSpecs: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
changeInformation: expect.objectContaining({
|
|
newTypes: expect.not.arrayContaining([expect.anything()]),
|
|
deprecatedTypes: expect.not.arrayContaining([
|
|
expect.anything(),
|
|
]),
|
|
incompatibleChanges: expect.not.arrayContaining([
|
|
expect.anything(),
|
|
]),
|
|
objectTypeChanges: expect.any(Object),
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
);
|
|
});
|
|
it('RN with enum types, and type changes', () => {
|
|
expect(
|
|
schemaDiffExporter(
|
|
Array.from(
|
|
buildSchemaDiff(
|
|
schemaWithEnumFromNative,
|
|
schemaWithEnumFromNativeTypeChanges,
|
|
),
|
|
)[0],
|
|
),
|
|
).toEqual(
|
|
expect.objectContaining({
|
|
framework: 'ReactNative',
|
|
status: expect.objectContaining({
|
|
incompatibleSpecs: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
changeInformation: expect.objectContaining({
|
|
incompatibleChanges: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
errorInformation: expect.objectContaining({
|
|
mismatchedProperties: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
fault: expect.objectContaining({
|
|
previousError: expect.objectContaining({
|
|
previousError: expect.objectContaining({
|
|
mismatchedProperties:
|
|
expect.arrayContaining([
|
|
expect.objectContaining({
|
|
fault: expect.objectContaining({
|
|
previousError:
|
|
expect.objectContaining({
|
|
message:
|
|
'EnumDeclaration member types are not the same',
|
|
}),
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
);
|
|
});
|
|
it('RN with enum types, and value changes', () => {
|
|
expect(
|
|
schemaDiffExporter(
|
|
Array.from(
|
|
buildSchemaDiff(
|
|
schemaWithEnumFromNative,
|
|
schemaWithEnumFromNativeValueChanges,
|
|
),
|
|
)[0],
|
|
),
|
|
).toEqual(
|
|
expect.objectContaining({
|
|
framework: 'ReactNative',
|
|
status: expect.objectContaining({
|
|
incompatibleSpecs: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
changeInformation: expect.objectContaining({
|
|
incompatibleChanges: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
errorInformation: expect.objectContaining({
|
|
mismatchedProperties: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
fault: expect.objectContaining({
|
|
previousError: expect.objectContaining({
|
|
previousError: expect.objectContaining({
|
|
mismatchedProperties:
|
|
expect.arrayContaining([
|
|
expect.objectContaining({
|
|
fault: expect.objectContaining({
|
|
previousError:
|
|
expect.objectContaining({
|
|
message:
|
|
'Enum types do not match',
|
|
previousError:
|
|
expect.objectContaining({
|
|
message:
|
|
'Enum contained a member with a type mismatch',
|
|
mismatchedMembers:
|
|
expect.arrayContaining([
|
|
expect.objectContaining(
|
|
{
|
|
member: 'B',
|
|
},
|
|
),
|
|
]),
|
|
}),
|
|
}),
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
);
|
|
});
|
|
});
|
|
});
|
|
|
|
it('RN with eventEmitters, same module', () => {
|
|
expect(
|
|
buildSchemaDiff(schemaWithEventEmitter, schemaWithEventEmitter),
|
|
).toEqual(new Set());
|
|
});
|
|
|
|
it('RN with eventEmitters, and eventType changes', () => {
|
|
expect(
|
|
schemaDiffExporter(
|
|
Array.from(
|
|
buildSchemaDiff(
|
|
schemaWithEventEmitter,
|
|
schemaWithEventEmitterChanges,
|
|
),
|
|
)[0],
|
|
),
|
|
).toEqual(
|
|
expect.objectContaining({
|
|
framework: 'ReactNative',
|
|
status: expect.objectContaining({
|
|
incompatibleSpecs: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
changeInformation: expect.objectContaining({
|
|
incompatibleChanges: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
errorInformation: expect.objectContaining({
|
|
message:
|
|
'Object contained properties with type mismatches',
|
|
mismatchedProperties: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
fault: expect.objectContaining({
|
|
message: 'has conflicting type changes',
|
|
previousError: expect.objectContaining({
|
|
message:
|
|
'EventEmitter eventTypes are not equivalent',
|
|
}),
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
);
|
|
});
|
|
|
|
it('RN with adding an optional argument to function', () => {
|
|
expect(
|
|
schemaDiffExporter(
|
|
Array.from(
|
|
buildSchemaDiff(schemaWithOptionalArgument, schemaWithRN),
|
|
)[0],
|
|
),
|
|
).toEqual(
|
|
expect.objectContaining({
|
|
framework: 'ReactNative',
|
|
status: expect.objectContaining({
|
|
incompatibleSpecs: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
changeInformation: expect.objectContaining({
|
|
incompatibleChanges: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
errorInformation: expect.objectContaining({
|
|
message:
|
|
'Object contained a property with a type mismatch',
|
|
mismatchedProperties: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
fault: expect.objectContaining({
|
|
message: 'has conflicting type changes',
|
|
previousError: expect.objectContaining({
|
|
message:
|
|
'Function types have differing length of arguments',
|
|
}),
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
);
|
|
});
|
|
|
|
it('RN with removing an optional argument to function', () => {
|
|
expect(
|
|
schemaDiffExporter(
|
|
Array.from(
|
|
buildSchemaDiff(schemaWithRN, schemaWithOptionalArgument),
|
|
)[0],
|
|
),
|
|
).toEqual(
|
|
expect.objectContaining({
|
|
framework: 'ReactNative',
|
|
status: expect.objectContaining({
|
|
incompatibleSpecs: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
changeInformation: expect.objectContaining({
|
|
incompatibleChanges: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
errorInformation: expect.objectContaining({
|
|
message:
|
|
'Object contained a property with a type mismatch',
|
|
mismatchedProperties: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
fault: expect.objectContaining({
|
|
message: 'has conflicting type changes',
|
|
previousError: expect.objectContaining({
|
|
message:
|
|
'Function types have differing length of arguments',
|
|
}),
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
);
|
|
});
|
|
|
|
it('RN with union types, same module', () => {
|
|
expect(buildSchemaDiff(schemaWithUnion, schemaWithUnion)).toEqual(
|
|
new Set(),
|
|
);
|
|
});
|
|
|
|
it('RN with union types, and addition', () => {
|
|
expect(
|
|
schemaDiffExporter(
|
|
Array.from(buildSchemaDiff(schemaWithUnionChanges, schemaWithUnion))[0],
|
|
),
|
|
).toEqual(
|
|
expect.objectContaining({
|
|
framework: 'ReactNative',
|
|
status: expect.objectContaining({
|
|
incompatibleSpecs: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
changeInformation: expect.objectContaining({
|
|
incompatibleChanges: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
errorInformation: expect.objectContaining({
|
|
message: addedUnionMessage,
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
);
|
|
});
|
|
it('RN with union types, and removal', () => {
|
|
expect(
|
|
schemaDiffExporter(
|
|
Array.from(buildSchemaDiff(schemaWithUnion, schemaWithUnionChanges))[0],
|
|
),
|
|
).toEqual(
|
|
expect.objectContaining({
|
|
status: expect.objectContaining({
|
|
incompatibleSpecs: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
changeInformation: expect.objectContaining({
|
|
newTypes: expect.not.arrayContaining([expect.anything()]),
|
|
deprecatedTypes: expect.not.arrayContaining([
|
|
expect.anything(),
|
|
]),
|
|
incompatibleChanges: expect.not.arrayContaining([
|
|
expect.anything(),
|
|
]),
|
|
objectTypeChanges: expect.any(Object),
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
);
|
|
});
|
|
it('RN with union types from native, and addition', () => {
|
|
expect(
|
|
schemaDiffExporter(
|
|
Array.from(
|
|
buildSchemaDiff(
|
|
schemaWithUnionFromNativeChanges,
|
|
schemaWithUnionFromNative,
|
|
),
|
|
)[0],
|
|
),
|
|
).toEqual(
|
|
expect.objectContaining({
|
|
status: expect.objectContaining({
|
|
incompatibleSpecs: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
changeInformation: expect.objectContaining({
|
|
newTypes: expect.not.arrayContaining([expect.anything()]),
|
|
deprecatedTypes: expect.not.arrayContaining([
|
|
expect.anything(),
|
|
]),
|
|
incompatibleChanges: expect.not.arrayContaining([
|
|
expect.anything(),
|
|
]),
|
|
objectTypeChanges: expect.any(Object),
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
);
|
|
});
|
|
it('RN with union types from native, and removal', () => {
|
|
expect(
|
|
schemaDiffExporter(
|
|
Array.from(
|
|
buildSchemaDiff(
|
|
schemaWithUnionFromNative,
|
|
schemaWithUnionFromNativeChanges,
|
|
),
|
|
)[0],
|
|
),
|
|
).toEqual(
|
|
expect.objectContaining({
|
|
framework: 'ReactNative',
|
|
status: expect.objectContaining({
|
|
incompatibleSpecs: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
changeInformation: expect.objectContaining({
|
|
incompatibleChanges: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
errorInformation: expect.objectContaining({
|
|
message: removedUnionMessage,
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
);
|
|
});
|
|
|
|
describe('NativeComponent', () => {
|
|
it('module to component; deprecated + new', () => {
|
|
expect(
|
|
Array.from(buildSchemaDiff(schemaWithRNNativeComponent, schemaWithRN)),
|
|
).toEqual(
|
|
expect.arrayContaining([
|
|
expect.objectContaining({
|
|
name: 'NativeComponent',
|
|
status: 'new',
|
|
}),
|
|
expect.objectContaining({
|
|
name: 'NativeModule',
|
|
status: 'deprecated',
|
|
}),
|
|
]),
|
|
);
|
|
});
|
|
|
|
it('component changed to module; deprecated + new', () => {
|
|
expect(
|
|
Array.from(buildSchemaDiff(schemaWithRN, schemaWithRNNativeComponent)),
|
|
).toEqual(
|
|
expect.arrayContaining([
|
|
expect.objectContaining({
|
|
name: 'NativeModule',
|
|
status: 'new',
|
|
}),
|
|
expect.objectContaining({
|
|
name: 'NativeComponent',
|
|
status: 'deprecated',
|
|
}),
|
|
]),
|
|
);
|
|
});
|
|
|
|
it('same RN component, no changes', () => {
|
|
expect(
|
|
buildSchemaDiff(
|
|
schemaWithRNNativeComponent,
|
|
schemaWithRNNativeComponent,
|
|
),
|
|
).toEqual(new Set());
|
|
});
|
|
|
|
describe('commands', () => {
|
|
it('Command with additional arg', () => {
|
|
expect(
|
|
schemaDiffExporter(
|
|
Array.from(
|
|
buildSchemaDiff(
|
|
schemaNativeComponentWithCommandExtraArg,
|
|
schemaNativeComponentWithCommand,
|
|
),
|
|
)[0],
|
|
),
|
|
).toEqual(
|
|
expect.objectContaining({
|
|
framework: 'ReactNative',
|
|
status: expect.objectContaining({
|
|
incompatibleSpecs: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
changeInformation: expect.objectContaining({
|
|
incompatibleChanges: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
errorInformation: expect.objectContaining({
|
|
mismatchedProperties: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
fault: expect.objectContaining({
|
|
previousError: expect.objectContaining({
|
|
message:
|
|
'Function types have differing length of arguments',
|
|
}),
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
);
|
|
});
|
|
|
|
it('Command with arg removed', () => {
|
|
expect(
|
|
schemaDiffExporter(
|
|
Array.from(
|
|
buildSchemaDiff(
|
|
schemaNativeComponentWithCommand,
|
|
schemaNativeComponentWithCommandExtraArg,
|
|
),
|
|
)[0],
|
|
),
|
|
).toEqual(
|
|
expect.objectContaining({
|
|
framework: 'ReactNative',
|
|
status: expect.objectContaining({
|
|
incompatibleSpecs: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
changeInformation: expect.objectContaining({
|
|
incompatibleChanges: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
errorInformation: expect.objectContaining({
|
|
mismatchedProperties: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
fault: expect.objectContaining({
|
|
previousError: expect.objectContaining({
|
|
message:
|
|
'Function types have differing length of arguments',
|
|
}),
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
);
|
|
});
|
|
|
|
it('1 command to 2 commands is allowed', () => {
|
|
// This could technically result in an OTA issue if the command
|
|
// is called immediately and the native side throws on unrecognized
|
|
// commands. However, there is no way to do feature detection
|
|
// of commands today to protect against that.
|
|
// We are choosing to allow this change to be made since we previously
|
|
// had no protection for commands at all.
|
|
// See https://fb.workplace.com/groups/615693552291894/posts/1905124013348835
|
|
// for more information.
|
|
expect(
|
|
summarizeDiffSet(
|
|
buildSchemaDiff(
|
|
schemaNativeComponentWithCommandExtraCommand,
|
|
schemaNativeComponentWithCommand,
|
|
),
|
|
).status,
|
|
).toEqual('ok');
|
|
});
|
|
|
|
it('2 commands to 1 command is allowed', () => {
|
|
expect(
|
|
summarizeDiffSet(
|
|
buildSchemaDiff(
|
|
schemaNativeComponentWithCommand,
|
|
schemaNativeComponentWithCommandExtraCommand,
|
|
),
|
|
).status,
|
|
).toEqual('ok');
|
|
});
|
|
|
|
it('0 commands to 1 command is allowed', () => {
|
|
expect(
|
|
summarizeDiffSet(
|
|
buildSchemaDiff(
|
|
schemaNativeComponentWithCommand,
|
|
schemaWithRNNativeComponent,
|
|
),
|
|
).status,
|
|
).toEqual('ok');
|
|
});
|
|
|
|
it('1 command to 0 commands is allowed', () => {
|
|
expect(
|
|
summarizeDiffSet(
|
|
buildSchemaDiff(
|
|
schemaWithRNNativeComponent,
|
|
schemaNativeComponentWithCommand,
|
|
),
|
|
).status,
|
|
).toEqual('ok');
|
|
});
|
|
});
|
|
|
|
describe('props', () => {
|
|
it('prop with changed value', () => {
|
|
expect(
|
|
schemaDiffExporter(
|
|
Array.from(
|
|
buildSchemaDiff(
|
|
schemaNativeComponentWithPropsChanges,
|
|
schemaNativeComponentWithProps,
|
|
),
|
|
)[0],
|
|
),
|
|
).toEqual(
|
|
expect.objectContaining({
|
|
framework: 'ReactNative',
|
|
status: expect.objectContaining({
|
|
incompatibleSpecs: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
changeInformation: expect.objectContaining({
|
|
incompatibleChanges: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
errorInformation: expect.objectContaining({
|
|
message:
|
|
'Object contained a property with a type mismatch',
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
);
|
|
});
|
|
|
|
it('prop with changed default value should be okay', () => {
|
|
expect(
|
|
summarizeDiffSet(
|
|
buildSchemaDiff(
|
|
schemaNativeComponentWithPropsDefaultChange,
|
|
schemaNativeComponentWithProps,
|
|
),
|
|
).status,
|
|
).toBe('ok');
|
|
});
|
|
|
|
it('props with optional prop added should be okay', () => {
|
|
expect(
|
|
summarizeDiffSet(
|
|
buildSchemaDiff(
|
|
schemaNativeComponentWithPropsAddedOptionalProp,
|
|
schemaNativeComponentWithProps,
|
|
),
|
|
).status,
|
|
).toBe('ok');
|
|
});
|
|
|
|
it('props with optional prop removed should be okay', () => {
|
|
expect(
|
|
summarizeDiffSet(
|
|
buildSchemaDiff(
|
|
schemaNativeComponentWithProps,
|
|
schemaNativeComponentWithPropsAddedOptionalProp,
|
|
),
|
|
).status,
|
|
).toBe('ok');
|
|
});
|
|
|
|
it('props with required prop added should be okay', () => {
|
|
expect(
|
|
summarizeDiffSet(
|
|
buildSchemaDiff(
|
|
schemaNativeComponentWithPropsAddedRequiredProp,
|
|
schemaNativeComponentWithProps,
|
|
),
|
|
).status,
|
|
).toBe('ok');
|
|
});
|
|
|
|
it('props with required prop removed should fail', () => {
|
|
expect(
|
|
schemaDiffExporter(
|
|
Array.from(
|
|
buildSchemaDiff(
|
|
schemaNativeComponentWithProps,
|
|
schemaNativeComponentWithPropsAddedRequiredProp,
|
|
),
|
|
)[0],
|
|
),
|
|
).toEqual(
|
|
expect.objectContaining({
|
|
framework: 'ReactNative',
|
|
status: expect.objectContaining({
|
|
incompatibleSpecs: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
changeInformation: expect.objectContaining({
|
|
incompatibleChanges: expect.objectContaining({
|
|
'0': expect.objectContaining({
|
|
errorInformation: expect.objectContaining({
|
|
message: removedPropertiesMessage,
|
|
}),
|
|
}),
|
|
}),
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
);
|
|
});
|
|
|
|
it('props with nested object, adding an optional key should be okay', () => {
|
|
expect(
|
|
summarizeDiffSet(
|
|
buildSchemaDiff(
|
|
schemaNativeComponentWithPropsNestedObjectAddedOptionalKey,
|
|
schemaNativeComponentWithPropsNestedObject,
|
|
),
|
|
).status,
|
|
).toBe('ok');
|
|
});
|
|
|
|
it('props with nested object, removing an optional key should be okay', () => {
|
|
expect(
|
|
summarizeDiffSet(
|
|
buildSchemaDiff(
|
|
schemaNativeComponentWithPropsNestedObject,
|
|
schemaNativeComponentWithPropsNestedObjectAddedOptionalKey,
|
|
),
|
|
).status,
|
|
).toBe('ok');
|
|
});
|
|
|
|
it('props with nested object, adding a required key should be okay', () => {
|
|
expect(
|
|
summarizeDiffSet(
|
|
buildSchemaDiff(
|
|
schemaNativeComponentWithPropsNestedObjectAddedRequiredKey,
|
|
schemaNativeComponentWithPropsNestedObject,
|
|
),
|
|
).status,
|
|
).toBe('ok');
|
|
});
|
|
|
|
it('props with union and added option should fail', () => {
|
|
expect(
|
|
schemaDiffExporter(
|
|
Array.from(
|
|
buildSchemaDiff(
|
|
schemaNativeComponentWithPropsUnionAdded,
|
|
schemaNativeComponentWithPropsUnion,
|
|
),
|
|
)[0],
|
|
),
|
|
).toEqual(
|
|
expect.objectContaining({
|
|
framework: 'ReactNative',
|
|
status: expect.objectContaining({
|
|
incompatibleSpecs: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
changeInformation: expect.objectContaining({
|
|
incompatibleChanges: expect.objectContaining({
|
|
'0': expect.objectContaining({
|
|
errorInformation: expect.objectContaining({
|
|
message: addedUnionMessage,
|
|
}),
|
|
}),
|
|
}),
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
);
|
|
});
|
|
|
|
it('props with union and removed option should be ok', () => {
|
|
expect(
|
|
summarizeDiffSet(
|
|
buildSchemaDiff(
|
|
schemaNativeComponentWithPropsUnion,
|
|
schemaNativeComponentWithPropsUnionAdded,
|
|
),
|
|
).status,
|
|
).toBe('ok');
|
|
});
|
|
|
|
it('props with array union and added option should fail', () => {
|
|
expect(
|
|
schemaDiffExporter(
|
|
Array.from(
|
|
buildSchemaDiff(
|
|
schemaNativeComponentWithPropsArrayUnionAdded,
|
|
schemaNativeComponentWithPropsArrayUnion,
|
|
),
|
|
)[0],
|
|
),
|
|
).toEqual(
|
|
expect.objectContaining({
|
|
framework: 'ReactNative',
|
|
status: expect.objectContaining({
|
|
incompatibleSpecs: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
changeInformation: expect.objectContaining({
|
|
incompatibleChanges: expect.objectContaining({
|
|
'0': expect.objectContaining({
|
|
errorInformation: expect.objectContaining({
|
|
message: addedUnionMessage,
|
|
}),
|
|
}),
|
|
}),
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
);
|
|
});
|
|
|
|
it('props with array union and removed option should be ok', () => {
|
|
// This is risky due to these being stored from component props codegen
|
|
// in C++ ints via bitshift which might change the resulting
|
|
// int value for the same inputs.
|
|
expect(
|
|
summarizeDiffSet(
|
|
buildSchemaDiff(
|
|
schemaNativeComponentWithPropsArrayUnion,
|
|
schemaNativeComponentWithPropsArrayUnionAdded,
|
|
),
|
|
).status,
|
|
).toBe('ok');
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('RN new codegen', () => {
|
|
describe('Native Module', () => {
|
|
it('removed', () => {
|
|
expect(
|
|
summarizeDiffSet(
|
|
buildSchemaDiff(schemaWithRNNativeComponent, schemaWithRN),
|
|
).status,
|
|
).toEqual('patchable');
|
|
});
|
|
it('added', () => {
|
|
expect(
|
|
schemaDiffExporter(
|
|
Array.from(
|
|
buildSchemaDiff(schemaWithRN, schemaWithRNNativeComponent),
|
|
)[0],
|
|
),
|
|
).toEqual(
|
|
expect.objectContaining({
|
|
name: 'NativeModule',
|
|
status: 'new',
|
|
}),
|
|
);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('RN NativeModule getConstants type diffing', () => {
|
|
it('should not allow required constants to be added to NativeModules', () => {
|
|
const schemaDiff = buildSchemaDiff(
|
|
schemaGetConstantsAddedRequiredConstant, // new
|
|
schemaGetConstants, // old
|
|
);
|
|
|
|
expect(summarizeDiffSet(schemaDiff).status).toBe('incompatible');
|
|
expect(schemaDiffExporter(Array.from(schemaDiff)[0])).toEqual(
|
|
expect.objectContaining({
|
|
status: expect.objectContaining({
|
|
incompatibleSpecs: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
changeInformation: expect.objectContaining({
|
|
incompatibleChanges: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
errorInformation: expect.objectContaining({
|
|
message: addedPropertiesMessage,
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
]),
|
|
}),
|
|
}),
|
|
);
|
|
});
|
|
|
|
it('should allow optional constants to be added to NativeModules', () => {
|
|
const schemaDiff = buildSchemaDiff(
|
|
schemaGetConstantsAddedOptionalConstant, // new
|
|
schemaGetConstants, // old
|
|
);
|
|
|
|
expect(summarizeDiffSet(schemaDiff).status).toBe('ok');
|
|
});
|
|
|
|
it('should allow removal of required constants from NativeModules', () => {
|
|
const schemaDiff = buildSchemaDiff(
|
|
schemaGetConstants, // new
|
|
schemaGetConstantsAddedRequiredConstant, // old
|
|
);
|
|
|
|
expect(summarizeDiffSet(schemaDiff).status).toBe('ok');
|
|
});
|
|
|
|
it('should allow removal of optional constants from NativeModules', () => {
|
|
const schemaDiff = buildSchemaDiff(
|
|
schemaGetConstants, // new
|
|
schemaGetConstantsAddedOptionalConstant, // old
|
|
);
|
|
|
|
expect(summarizeDiffSet(schemaDiff).status).toBe('ok');
|
|
});
|
|
|
|
it('should not allow promotion of optional constants to required constants', () => {
|
|
const schemaDiff = buildSchemaDiff(
|
|
schemaGetConstantsAddedRequiredConstant, // new
|
|
schemaGetConstantsAddedOptionalConstant, // old
|
|
);
|
|
|
|
expect(summarizeDiffSet(schemaDiff).status).toBe('incompatible');
|
|
});
|
|
|
|
it('should allow required constants to become optional constants', () => {
|
|
const schemaDiff = buildSchemaDiff(
|
|
schemaGetConstantsAddedOptionalConstant, // new
|
|
schemaGetConstantsAddedRequiredConstant, // old
|
|
);
|
|
|
|
expect(summarizeDiffSet(schemaDiff).status).toBe('ok');
|
|
});
|
|
});
|
|
|
|
describe('RN NativeModule getConstants $ReadOnly type diffing', () => {
|
|
it('should not allow required constants to be added to NativeModules', () => {
|
|
const schemaDiff = buildSchemaDiff(
|
|
schemaGetConstantsAddedRequiredConstantReadOnly, // new
|
|
schemaGetConstantsReadOnly, // old
|
|
);
|
|
|
|
expect(summarizeDiffSet(schemaDiff).status).toBe('incompatible');
|
|
});
|
|
|
|
it('should allow optional constants to be added to NativeModules', () => {
|
|
const schemaDiff = buildSchemaDiff(
|
|
schemaGetConstantsAddedOptionalConstantReadOnly, // new
|
|
schemaGetConstantsReadOnly, // old
|
|
);
|
|
|
|
expect(summarizeDiffSet(schemaDiff).status).toBe('ok');
|
|
});
|
|
|
|
it('should allow removal of required constants from NativeModules', () => {
|
|
const schemaDiff = buildSchemaDiff(
|
|
schemaGetConstantsReadOnly, // new
|
|
schemaGetConstantsAddedRequiredConstantReadOnly, // old
|
|
);
|
|
|
|
expect(summarizeDiffSet(schemaDiff).status).toBe('ok');
|
|
});
|
|
|
|
it('should allow removal of optional constants from NativeModules', () => {
|
|
const schemaDiff = buildSchemaDiff(
|
|
schemaGetConstantsReadOnly, // new
|
|
schemaGetConstantsAddedOptionalConstantReadOnly, // old
|
|
);
|
|
|
|
expect(summarizeDiffSet(schemaDiff).status).toBe('ok');
|
|
});
|
|
|
|
it('should not allow promotion of optional constants to required constants', () => {
|
|
const schemaDiff = buildSchemaDiff(
|
|
schemaGetConstantsAddedRequiredConstantReadOnly, // new
|
|
schemaGetConstantsAddedOptionalConstantReadOnly, // old
|
|
);
|
|
|
|
expect(summarizeDiffSet(schemaDiff).status).toBe('incompatible');
|
|
});
|
|
|
|
it('should allow required constants to become optional constants', () => {
|
|
const schemaDiff = buildSchemaDiff(
|
|
schemaGetConstantsAddedOptionalConstantReadOnly, // new
|
|
schemaGetConstantsAddedRequiredConstantReadOnly, // old
|
|
);
|
|
|
|
expect(summarizeDiffSet(schemaDiff).status).toBe('ok');
|
|
});
|
|
});
|
|
|
|
describe('summarizeDiffSet', () => {
|
|
const set = new Set<SchemaDiff>();
|
|
it('is given empty set', () => {
|
|
expect(summarizeDiffSet(set).status).toBe('ok');
|
|
});
|
|
it('is given set with one new', () => {
|
|
set.add({
|
|
name: 'SampleName',
|
|
framework: 'ReactNative',
|
|
status: 'new',
|
|
});
|
|
expect(summarizeDiffSet(set).status).toBe('patchable');
|
|
});
|
|
it('is given complex set', () => {
|
|
expect(
|
|
summarizeDiffSet(
|
|
buildSchemaDiff(
|
|
schemaBeforeAfterTypes,
|
|
schemaBeforeAfterTypesTypesRemoved,
|
|
),
|
|
).status,
|
|
).toBe('incompatible');
|
|
});
|
|
it('is given a diff that has incompatible changes in the boundary', () => {
|
|
expect(
|
|
summarizeDiffSet(
|
|
buildSchemaDiff(
|
|
schemaBeforeAfterTypes,
|
|
schemaBeforeAfterTypesTypeChanged,
|
|
),
|
|
).status,
|
|
).toBe('incompatible');
|
|
});
|
|
});
|