Improve CI builds relying on Chrome (#796)

* Use ES6 Proxies to implement collections in the Chrome debugger

* rework realm-test-names event

* move React stuff on the CPH mac mini

* use node with npm3

* remove debugging aid code
This commit is contained in:
Yavor Georgiev 2017-01-11 18:22:41 +01:00 committed by GitHub
parent 35c21c203f
commit 12bde1ed35
6 changed files with 92 additions and 74 deletions

19
Jenkinsfile vendored
View File

@ -68,8 +68,8 @@ stage('build') {
macos_node_release: doMacBuild('node Release'),
macos_realmjs_debug: doMacBuild('realmjs Debug'),
macos_realmjs_release: doMacBuild('realmjs Release'),
macos_react_tests_debug: doMacBuild('react-tests Debug'),
macos_react_tests_release: doMacBuild('react-tests Release'),
macos_react_tests_debug: doReactBuild('react-tests Debug'),
macos_react_tests_release: doReactBuild('react-tests Release'),
macos_react_example_debug: doMacBuild('react-example Debug'),
macos_react_example_release: doMacBuild('react-example Release'),
android_react_tests: doAndroidBuild('react-tests-android', {
@ -184,3 +184,18 @@ def doMacBuild(target, postStep = null) {
}
}
}
def doReactBuild(target, postStep = null) {
return {
node('xamarin-mac') {
try {
lock("${env.NODE_NAME} iOS Simulator") {
doInside("./scripts/test.sh", target, postStep)
}
} finally {
deleteDir()
}
}
}
}

View File

@ -19,7 +19,8 @@
'use strict';
import { keys } from './constants';
import { getterForProperty, setterForProperty } from './util';
import { getterForProperty } from './util';
import { getProperty, setProperty } from './rpc';
let mutationListeners = {};
@ -52,9 +53,65 @@ export function fireMutationListeners(realmId) {
}
}
function isIndex(propertyName) {
return typeof propertyName === 'number' || (typeof propertyName === 'string' && /^\d+$/.test(propertyName));
}
const mutable = Symbol('mutable');
const traps = {
get(collection, property, receiver) {
if (isIndex(property)) {
return getProperty(collection[keys.realm], collection[keys.id], property);
}
return Reflect.get(collection, property, collection);
},
set(collection, property, value, receiver) {
if (isIndex(property)) {
if (!collection[mutable]) {
return false;
}
setProperty(collection[keys.realm], collection[keys.id], property, value);
// If this isn't a primitive value, then it might create a new object in the Realm.
if (value && typeof value == 'object') {
fireMutationListeners(collection[keys.realm]);
}
return true;
}
return Reflect.set(collection, property, value, collection);
},
ownKeys(collection) {
return Reflect.ownKeys(collection).concat(Array.from({ length: collection.length }, (value, key) => String(key)));
},
getOwnPropertyDescriptor(collection, property) {
if (isIndex(property)) {
let descriptor = {
enumerable: true,
configurable: true,
writable: collection[mutable]
};
Reflect.defineProperty(descriptor, "value", { get: () => this.get(collection, property) });
return descriptor;
}
return Reflect.getOwnPropertyDescriptor(collection, property);
},
has(collection, property) {
if (isIndex(property)) {
return true;
}
return Reflect.has(collection, property);
}
};
export function createCollection(prototype, realmId, info, _mutable) {
let collection = Object.create(prototype);
let size;
Object.defineProperties(collection, {
'length': {
@ -65,65 +122,10 @@ export function createCollection(prototype, realmId, info, _mutable) {
},
});
let resize = function(length) {
if (length == null) {
length = collection.length;
}
if (length == size) {
return; // Nothing has changed.
}
if (size == null) {
size = 0; // This is first pass.
}
let props = {};
if (length > size) {
for (let i = size; i < length; i++) {
props[i] = {
get: getterForProperty(i),
set: setterForProperty(i),
enumerable: true,
configurable: true,
};
}
}
else if (length < size) {
for (let i = size; i >= length; i--) {
delete collection[i];
}
}
// Helpfully throw an exception on attempts to set to one past the last index.
props[length] = {
get: getterForProperty(length),
set: setterForProperty(length),
configurable: true,
};
Object.defineProperties(collection, props);
size = length;
};
collection[keys.realm] = realmId;
collection[keys.id] = info.id;
collection[keys.type] = info.type;
collection[mutable] = _mutable;
resize(info.size);
addMutationListener(realmId, function listener() {
try {
resize();
} catch (e) {
// If the error indicates the collection was deleted, then remove this listener.
if (e.message.indexOf('Access to invalidated') == 0) {
removeMutationListener(realmId, listener);
} else {
throw e;
}
}
});
return collection;
return new Proxy(collection, traps);
}

View File

@ -27,7 +27,7 @@ export const propTypes = {};
'realm',
'type',
].forEach(function(name) {
keys[name] = Symbol();
keys[name] = Symbol(name);
});
[

View File

@ -224,11 +224,14 @@ cleanup
trap cleanup EXIT
# Use a consistent version of Node if possible.
if [ -s "${HOME}/.nvm/nvm.sh" ]; then
# shellcheck disable=SC1090
. "${HOME}/.nvm/nvm.sh"
nvm use 5.12 || true
if [ -f "$NVM_DIR/nvm.sh" ]; then
. "$NVM_DIR/nvm.sh"
elif [ -x "$(command -v brew)" ] && [ -f "$(brew --prefix nvm)/nvm.sh" ]; then
# we must be on mac and nvm was installed with brew
# TODO: change the mac slaves to use manual nvm installation
. "$(brew --prefix nvm)/nvm.sh"
fi
[[ "$(command -v nvm)" ]] && nvm use 6.5.0 || true
# Remove cached packages
rm -rf ~/.yarn-cache/npm-realm-*

View File

@ -125,6 +125,7 @@ extern NSMutableArray *RCTGetModuleClasses(void);
JSGlobalContextSetIncludesNativeCallStackWhenReportingExceptions(ctx, false);
}
[self.currentBridge.eventDispatcher sendAppEventWithName:@"realm-test-names" body:nil];
NSDictionary *testCaseNames = [self waitForEvent:@"realm-test-names"];
NSAssert(testCaseNames.count, @"No test names were provided by the JS");

View File

@ -26,6 +26,11 @@ RealmTests.registerTests({
ListViewTest,
});
// Listen for event signalling native is ready to receive test names
NativeAppEventEmitter.addListener('realm-test-names', () => {
NativeModules.Realm.emit('realm-test-names', getTestNames());
});
// Listen for event to run a particular test.
NativeAppEventEmitter.addListener('realm-run-test', async ({suite, name}) => {
let error;
@ -38,14 +43,6 @@ NativeAppEventEmitter.addListener('realm-run-test', async ({suite, name}) => {
NativeModules.Realm.emit('realm-test-finished', error);
});
// Inform the native test harness about the test suite once it's ready.
setTimeout(() => {
// The emit() method only exists on iOS, for now.
if (NativeModules.Realm.emit) {
NativeModules.Realm.emit('realm-test-names', getTestNames());
}
}, 500);
export function getTestNames() {
return RealmTests.getTestNames();
}