@dcl/sdk 7.1.4-4578951400.commit-3810356 → 7.1.4-4598967522.commit-538c49d
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +6 -6
- package/src/testing/assert.ts +134 -0
- package/src/testing/index.ts +42 -0
- package/src/testing/runtime.ts +223 -0
- package/src/testing/types.ts +21 -0
- package/testing/assert.d.ts +11 -0
- package/testing/assert.js +106 -0
- package/testing/index.d.ts +2 -0
- package/testing/index.js +30 -0
- package/testing/runtime.d.ts +5 -0
- package/testing/runtime.js +168 -0
- package/testing/types.d.ts +13 -0
- package/testing/types.js +2 -0
- package/types/tsconfig.ecs7.strict.json +1 -3
- package/README.md +0 -0
- package/tsconfig.cli.json +0 -24
package/package.json
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
{
|
2
2
|
"name": "@dcl/sdk",
|
3
3
|
"description": "",
|
4
|
-
"version": "7.1.4-
|
4
|
+
"version": "7.1.4-4598967522.commit-538c49d",
|
5
5
|
"author": "Decentraland",
|
6
6
|
"dependencies": {
|
7
|
-
"@dcl/ecs": "7.1.4-
|
7
|
+
"@dcl/ecs": "7.1.4-4598967522.commit-538c49d",
|
8
8
|
"@dcl/ecs-math": "2.0.1-20221129185242.commit-40495c1",
|
9
9
|
"@dcl/explorer": "1.0.92953-20230320185045.commit-aed694a",
|
10
|
-
"@dcl/js-runtime": "7.1.4-
|
11
|
-
"@dcl/react-ecs": "7.1.4-
|
12
|
-
"@dcl/sdk-commands": "7.1.4-
|
10
|
+
"@dcl/js-runtime": "7.1.4-4598967522.commit-538c49d",
|
11
|
+
"@dcl/react-ecs": "7.1.4-4598967522.commit-538c49d",
|
12
|
+
"@dcl/sdk-commands": "7.1.4-4598967522.commit-538c49d"
|
13
13
|
},
|
14
14
|
"keywords": [],
|
15
15
|
"license": "Apache-2.0",
|
@@ -30,5 +30,5 @@
|
|
30
30
|
},
|
31
31
|
"types": "./index.d.ts",
|
32
32
|
"typings": "./index.d.ts",
|
33
|
-
"commit": "
|
33
|
+
"commit": "538c49d420ba1bf75ad9e6d821aec3c4afe26c69"
|
34
34
|
}
|
@@ -0,0 +1,134 @@
|
|
1
|
+
// VERBATIM COPY OF https://github.com/LemonPi/deep-close-to
|
2
|
+
|
3
|
+
import type { Entity, LastWriteWinElementSetComponentDefinition } from '@dcl/ecs'
|
4
|
+
|
5
|
+
const pSlice = Array.prototype.slice
|
6
|
+
|
7
|
+
const floatEpsilon = 0.0000001
|
8
|
+
|
9
|
+
type Options = { strict: boolean; comp: typeof closeTo }
|
10
|
+
|
11
|
+
export function assertEquals(a: any, b: any, message: string = 'Values are not equal') {
|
12
|
+
if (!deepCloseTo(a, b)) throw new Error(`${message} - ${JSON.stringify(a)} != ${JSON.stringify(b)}`)
|
13
|
+
}
|
14
|
+
|
15
|
+
export function assert(a: any, message: string = 'assertion failed') {
|
16
|
+
if (!a) throw new Error(message)
|
17
|
+
}
|
18
|
+
|
19
|
+
export function assertComponentValue<T>(
|
20
|
+
entity: Entity,
|
21
|
+
component: LastWriteWinElementSetComponentDefinition<T>,
|
22
|
+
value: T
|
23
|
+
) {
|
24
|
+
assert(component.has(entity), `The entity doesn't have a ${component.componentName} component`)
|
25
|
+
assertEquals(component.get(entity)!, value, `Invalid ${component.componentName} values`)
|
26
|
+
}
|
27
|
+
|
28
|
+
export function deepCloseTo(actual: any, expected: any, options: Partial<Options> = {}): boolean {
|
29
|
+
const opts = Object.assign({}, { comp: closeTo }, options)
|
30
|
+
// 7.1. All identical values are equivalent, as determined by ===.
|
31
|
+
if (actual === expected) {
|
32
|
+
return true
|
33
|
+
} else if (actual instanceof Date && expected instanceof Date) {
|
34
|
+
return opts.comp!(actual, expected)
|
35
|
+
|
36
|
+
// 7.3. Other pairs that do not both pass typeof value == 'object',
|
37
|
+
// equivalence is determined by ==.
|
38
|
+
} else if (!actual || !expected || (typeof actual !== 'object' && typeof expected !== 'object')) {
|
39
|
+
if (opts.strict) {
|
40
|
+
if (!actual && !expected) {
|
41
|
+
return actual === expected
|
42
|
+
}
|
43
|
+
|
44
|
+
if (typeof actual !== typeof expected) {
|
45
|
+
return false
|
46
|
+
}
|
47
|
+
}
|
48
|
+
if (!actual && !expected) {
|
49
|
+
return actual === expected
|
50
|
+
}
|
51
|
+
return opts.comp!(actual, expected)
|
52
|
+
|
53
|
+
// 7.4. For all other Object pairs, including Array objects, equivalence is
|
54
|
+
// determined by having the same number of owned properties (as verified
|
55
|
+
// with Object.prototype.hasOwnProperty.call), the same set of keys
|
56
|
+
// (although not necessarily the same order), equivalent values for every
|
57
|
+
// corresponding key, and an identical 'prototype' property. Note: this
|
58
|
+
// accounts for both named and indexed properties on Arrays.
|
59
|
+
} else {
|
60
|
+
return objEquiv(actual, expected, opts as any)
|
61
|
+
}
|
62
|
+
}
|
63
|
+
|
64
|
+
function isUndefinedOrNull(value: any) {
|
65
|
+
return value === null || value === undefined
|
66
|
+
}
|
67
|
+
|
68
|
+
function isBuffer(x: any) {
|
69
|
+
if (!x || typeof x !== 'object' || typeof x.length !== 'number') return false
|
70
|
+
if (typeof x.copy !== 'function' || typeof x.slice !== 'function') {
|
71
|
+
return false
|
72
|
+
}
|
73
|
+
if (x.length > 0 && typeof x[0] !== 'number') return false
|
74
|
+
return true
|
75
|
+
}
|
76
|
+
|
77
|
+
function objEquiv(a: any, b: any, opts: Options) {
|
78
|
+
let i, key
|
79
|
+
if (isUndefinedOrNull(a) || isUndefinedOrNull(b)) return false
|
80
|
+
// an identical 'prototype' property.
|
81
|
+
if (a.prototype !== b.prototype) return false
|
82
|
+
//~~~I've managed to break Object.keys through screwy arguments passing.
|
83
|
+
// Converting to array solves the problem.
|
84
|
+
if (isArguments(a)) {
|
85
|
+
if (!isArguments(b)) {
|
86
|
+
return false
|
87
|
+
}
|
88
|
+
return deepCloseTo(pSlice.call(a), pSlice.call(b), opts)
|
89
|
+
}
|
90
|
+
if (isBuffer(a)) {
|
91
|
+
if (!isBuffer(b)) {
|
92
|
+
return false
|
93
|
+
}
|
94
|
+
if (a.length !== b.length) return false
|
95
|
+
for (i = 0; i < a.length; i++) {
|
96
|
+
if (a[i] !== b[i]) return false
|
97
|
+
}
|
98
|
+
return true
|
99
|
+
}
|
100
|
+
|
101
|
+
try {
|
102
|
+
const ka = Object.keys(a)
|
103
|
+
const kb = Object.keys(b)
|
104
|
+
|
105
|
+
// having the same number of owned properties (keys incorporates
|
106
|
+
// hasOwnProperty)
|
107
|
+
if (ka.length !== kb.length) return false
|
108
|
+
//the same set of keys (although not necessarily the same order),
|
109
|
+
ka.sort()
|
110
|
+
kb.sort()
|
111
|
+
//~~~cheap key test
|
112
|
+
for (i = ka.length - 1; i >= 0; i--) {
|
113
|
+
if (ka[i] !== kb[i]) return false
|
114
|
+
}
|
115
|
+
//equivalent values for every corresponding key, and
|
116
|
+
//~~~possibly expensive deep test
|
117
|
+
for (i = ka.length - 1; i >= 0; i--) {
|
118
|
+
key = ka[i]
|
119
|
+
if (!deepCloseTo(a[key], b[key], opts)) return false
|
120
|
+
}
|
121
|
+
} catch (e) {
|
122
|
+
//happens when one is a string literal and the other isn't
|
123
|
+
return false
|
124
|
+
}
|
125
|
+
|
126
|
+
return typeof a === typeof b
|
127
|
+
}
|
128
|
+
|
129
|
+
function isArguments(object: any) {
|
130
|
+
return Object.prototype.toString.call(object) === '[object Arguments]'
|
131
|
+
}
|
132
|
+
function closeTo(actual: any, expected: any, delta: number = floatEpsilon) {
|
133
|
+
return Math.abs(actual - expected) < delta
|
134
|
+
}
|
@@ -0,0 +1,42 @@
|
|
1
|
+
import { engine } from '@dcl/ecs'
|
2
|
+
import { createTestRuntime } from './runtime'
|
3
|
+
import { TestDefinitionFunction, TestingModule } from './types'
|
4
|
+
|
5
|
+
declare let require: any
|
6
|
+
|
7
|
+
/**
|
8
|
+
* In development builds, this function serves as test runner for automated test scenarios
|
9
|
+
* if the runtime accepts the `~system/Testing` module
|
10
|
+
* @public
|
11
|
+
*/
|
12
|
+
/* @__PURE__ */
|
13
|
+
export const test: TestDefinitionFunction = DEBUG ? /* @__PURE__ */ createTestFunction() : /* @__PURE__ */ () => {}
|
14
|
+
|
15
|
+
function createTestFunction() {
|
16
|
+
let testingModule: TestingModule
|
17
|
+
try {
|
18
|
+
testingModule = /* @__PURE__ */ require('~system/Testing')
|
19
|
+
} catch (err) {
|
20
|
+
console.error(err)
|
21
|
+
|
22
|
+
console.error(`🔴🚨‼️ WARNING: The test runner is not available. The test runner will be mocked. ‼️🚨🔴`)
|
23
|
+
|
24
|
+
testingModule = {
|
25
|
+
async logTestResult(data) {
|
26
|
+
console.log(`🧪 mocked '~system/Testing'.logResult`, data)
|
27
|
+
return {}
|
28
|
+
},
|
29
|
+
async plan(data) {
|
30
|
+
console.log(`🧪 mocked '~system/Testing'.plan`, data)
|
31
|
+
return {}
|
32
|
+
},
|
33
|
+
async setCameraTransform(transform) {
|
34
|
+
console.log(`🧪 mocked '~system/Testing'.setCameraTransform`, transform)
|
35
|
+
return {}
|
36
|
+
}
|
37
|
+
}
|
38
|
+
}
|
39
|
+
|
40
|
+
const runtime = createTestRuntime(testingModule, engine)
|
41
|
+
return runtime.test
|
42
|
+
}
|
@@ -0,0 +1,223 @@
|
|
1
|
+
/**
|
2
|
+
* This module provides a createTestRuntime function that returns an object with a test function that can be used to define tests.
|
3
|
+
*/
|
4
|
+
|
5
|
+
import { IEngine, Transform } from '@dcl/ecs'
|
6
|
+
import { assertEquals } from './assert'
|
7
|
+
import type { TestingModule, TestFunction, TestHelpers } from './types'
|
8
|
+
|
9
|
+
// This function creates a test runtime that can be used to define and run tests.
|
10
|
+
// It takes a `TestingModule` instance (loaded from require('~system/Testing')) and an `IEngine` instance (from Decentraland's SDK).
|
11
|
+
// It returns an object with a `test` function that can be used to define tests.
|
12
|
+
/* @__PURE__ */
|
13
|
+
export function createTestRuntime(testingModule: TestingModule, engine: IEngine) {
|
14
|
+
type TestPlanEntry = { name: string; fn: TestFunction }
|
15
|
+
type RunnerEnvironment = {
|
16
|
+
resolve: () => void
|
17
|
+
reject: (error: any) => void
|
18
|
+
helpers: TestHelpers
|
19
|
+
generator: Generator
|
20
|
+
}
|
21
|
+
|
22
|
+
// this flag ensures no tests are added asynchronously
|
23
|
+
let runtimeFrozen = false
|
24
|
+
|
25
|
+
let currentFrameCounter = 0
|
26
|
+
let currentFrameTime = 0
|
27
|
+
|
28
|
+
// array to hold the scheduled tests
|
29
|
+
const scheduledTests: TestPlanEntry[] = []
|
30
|
+
|
31
|
+
// an array of promises that are resolved on the next frame (after the current frame is finished)
|
32
|
+
const nextTickFuture: Array<(dt: number) => void> = []
|
33
|
+
|
34
|
+
// this function returns a promise that resolves on the next frame
|
35
|
+
async function nextTick() {
|
36
|
+
return new Promise<number>((resolve) => {
|
37
|
+
nextTickFuture.push(resolve)
|
38
|
+
})
|
39
|
+
}
|
40
|
+
|
41
|
+
// add a system to the engine that resolves all promises in the `nextTickFuture` array
|
42
|
+
engine.addSystem(function TestingFrameworkCoroutineRunner(dt) {
|
43
|
+
currentFrameCounter++
|
44
|
+
currentFrameTime += dt
|
45
|
+
// resolve all nextTick futures.
|
46
|
+
nextTickFuture.splice(0, nextTickFuture.length).forEach((_) => _(dt))
|
47
|
+
})
|
48
|
+
|
49
|
+
// this function schedules a value to be processed on the next frame, the test runner will
|
50
|
+
// continue to run until it reaches a yield point
|
51
|
+
function scheduleValue(value: any, env: RunnerEnvironment) {
|
52
|
+
if (value && typeof value === 'object' && typeof value.then === 'function') {
|
53
|
+
console.log('⏱️ yield promise')
|
54
|
+
// if the value is a promise, schedule it to be awaited after the current frame is finished
|
55
|
+
nextTickFuture.push(async () => {
|
56
|
+
try {
|
57
|
+
scheduleValue(await value, env)
|
58
|
+
} catch (err) {
|
59
|
+
env.reject(err)
|
60
|
+
}
|
61
|
+
})
|
62
|
+
} else if (typeof value === 'function') {
|
63
|
+
console.log('⏱️ yield function')
|
64
|
+
// if the value is a function, schedule it to be called on the next frame
|
65
|
+
nextTickFuture.push(() => {
|
66
|
+
scheduleValue(value(), env)
|
67
|
+
})
|
68
|
+
return
|
69
|
+
} else if (typeof value === 'undefined' || value === null) {
|
70
|
+
console.log('⏱️ yield')
|
71
|
+
// if the value is undefined or null, continue processing the generator the next frame
|
72
|
+
nextTickFuture.push(() => {
|
73
|
+
consumeGenerator(env)
|
74
|
+
})
|
75
|
+
} else throw new Error(`Unexpected value from test generator: ${value}`)
|
76
|
+
}
|
77
|
+
|
78
|
+
// this function processes a generator function by scheduling its values to be processed on the next frame
|
79
|
+
function consumeGenerator(env: RunnerEnvironment) {
|
80
|
+
try {
|
81
|
+
const ret = env.generator.next()
|
82
|
+
if (!ret.done) {
|
83
|
+
scheduleValue(ret.value, env)
|
84
|
+
} else {
|
85
|
+
env.resolve()
|
86
|
+
}
|
87
|
+
} catch (err) {
|
88
|
+
env.reject(err)
|
89
|
+
}
|
90
|
+
}
|
91
|
+
|
92
|
+
// this function schedules a test run on the next frame
|
93
|
+
function scheduleNextRun() {
|
94
|
+
if (scheduledTests.length) {
|
95
|
+
nextTickFuture.push(runTests)
|
96
|
+
}
|
97
|
+
}
|
98
|
+
|
99
|
+
// this function runs the scheduled tests
|
100
|
+
function runTests() {
|
101
|
+
if (scheduledTests.length) {
|
102
|
+
const entry = scheduledTests.shift()!
|
103
|
+
const initialFrame = currentFrameCounter
|
104
|
+
const startTime = currentFrameTime
|
105
|
+
|
106
|
+
let resolved = false
|
107
|
+
|
108
|
+
// this function should be called only once. it makes the current test pass
|
109
|
+
const resolve = () => {
|
110
|
+
if (resolved) throw new Error('resolved twice')
|
111
|
+
resolved = true
|
112
|
+
|
113
|
+
console.log(`🟢 Test passed ${entry.name}`)
|
114
|
+
|
115
|
+
testingModule
|
116
|
+
.logTestResult({
|
117
|
+
name: entry.name,
|
118
|
+
ok: true,
|
119
|
+
totalFrames: currentFrameCounter - initialFrame,
|
120
|
+
totalTime: currentFrameTime - startTime
|
121
|
+
})
|
122
|
+
.finally(scheduleNextRun)
|
123
|
+
}
|
124
|
+
|
125
|
+
const reject = (err: any) => {
|
126
|
+
if (resolved) throw new Error('resolved twice')
|
127
|
+
resolved = true
|
128
|
+
|
129
|
+
console.log(`🔴 Test failed ${entry.name}`)
|
130
|
+
console.error(err)
|
131
|
+
|
132
|
+
testingModule
|
133
|
+
.logTestResult({
|
134
|
+
name: entry.name,
|
135
|
+
ok: false,
|
136
|
+
error: err.toString(),
|
137
|
+
stack: err && typeof err === 'object' && err.stack,
|
138
|
+
totalFrames: currentFrameCounter - initialFrame,
|
139
|
+
totalTime: currentFrameTime - startTime
|
140
|
+
})
|
141
|
+
.finally(scheduleNextRun)
|
142
|
+
}
|
143
|
+
|
144
|
+
try {
|
145
|
+
console.log(`🧪 Running test ${entry.name}`)
|
146
|
+
|
147
|
+
const testHelpers: TestHelpers = {
|
148
|
+
async setCameraTransform(transform) {
|
149
|
+
await testingModule.setCameraTransform(transform)
|
150
|
+
await nextTick()
|
151
|
+
|
152
|
+
const TransformComponent = engine.getComponent(Transform.componentId) as typeof Transform
|
153
|
+
const actualTransform = TransformComponent.get(engine.CameraEntity)
|
154
|
+
|
155
|
+
assertEquals(actualTransform.position, transform.position, "positions don't match")
|
156
|
+
assertEquals(actualTransform.rotation, transform.rotation, "rotations don't match")
|
157
|
+
}
|
158
|
+
}
|
159
|
+
|
160
|
+
const returnValue = entry.fn(testHelpers)
|
161
|
+
|
162
|
+
if (returnValue && typeof returnValue === 'object') {
|
163
|
+
if (isGenerator(returnValue)) {
|
164
|
+
const env: RunnerEnvironment = {
|
165
|
+
generator: returnValue,
|
166
|
+
helpers: testHelpers,
|
167
|
+
resolve,
|
168
|
+
reject
|
169
|
+
}
|
170
|
+
consumeGenerator(env)
|
171
|
+
} else if (isPromise(returnValue)) {
|
172
|
+
returnValue.then(resolve).catch(reject)
|
173
|
+
} else {
|
174
|
+
throw new Error(`Unknown test result type: ${returnValue}`)
|
175
|
+
}
|
176
|
+
} else {
|
177
|
+
resolve()
|
178
|
+
}
|
179
|
+
} catch (err: any) {
|
180
|
+
reject(err)
|
181
|
+
}
|
182
|
+
}
|
183
|
+
}
|
184
|
+
|
185
|
+
// schedule the test runner start for the next frame
|
186
|
+
nextTickFuture.push(() => {
|
187
|
+
// once we run the next tick, the test runtime becomes frozen. that means no new
|
188
|
+
// test definitions are accepted
|
189
|
+
runtimeFrozen = true
|
190
|
+
|
191
|
+
if (!scheduledTests.length) return
|
192
|
+
|
193
|
+
// inform the test runner about the plans for this test run
|
194
|
+
testingModule.plan({ tests: scheduledTests }).then(scheduleNextRun).catch(globalFail)
|
195
|
+
})
|
196
|
+
|
197
|
+
// this is the function that is used to plan a test functionn
|
198
|
+
/* @__PURE__ */
|
199
|
+
function test(name: string, fn: TestFunction) {
|
200
|
+
if (runtimeFrozen) throw new Error("New tests can't be added at this stage.")
|
201
|
+
|
202
|
+
if (scheduledTests.some(($) => $.name === name)) throw new Error(`Test with name ${name} already exists`)
|
203
|
+
|
204
|
+
scheduledTests.push({ fn, name })
|
205
|
+
}
|
206
|
+
|
207
|
+
return {
|
208
|
+
test
|
209
|
+
}
|
210
|
+
}
|
211
|
+
|
212
|
+
function isGenerator(t: any): t is Generator {
|
213
|
+
return t && typeof t === 'object' && typeof t[Symbol.iterator] === 'function'
|
214
|
+
}
|
215
|
+
|
216
|
+
function isPromise(t: any): t is Promise<unknown> {
|
217
|
+
return t && typeof t === 'object' && typeof t.then === 'function'
|
218
|
+
}
|
219
|
+
|
220
|
+
function globalFail(error: any) {
|
221
|
+
// for now, the failure is only writing to the console.error.
|
222
|
+
console.error(error)
|
223
|
+
}
|
@@ -0,0 +1,21 @@
|
|
1
|
+
import type { TransformType } from '@dcl/ecs'
|
2
|
+
import type { logTestResult, plan, setCameraTransform } from '~system/Testing'
|
3
|
+
|
4
|
+
export type TestHelpers = {
|
5
|
+
/**
|
6
|
+
* Instructs the renderer to set the camera transform to the provided argument.
|
7
|
+
* This function resolves the next frame and fails if the CameraTransform is not
|
8
|
+
* equal to the provided argument.
|
9
|
+
*/
|
10
|
+
setCameraTransform(transform: Pick<TransformType, 'position' | 'rotation'>): Promise<void>
|
11
|
+
}
|
12
|
+
|
13
|
+
export type TestFunction = (helpers: TestHelpers) => Generator | Promise<any>
|
14
|
+
|
15
|
+
export type TestDefinitionFunction = (name: string, fn: TestFunction) => void
|
16
|
+
|
17
|
+
export type TestingModule = {
|
18
|
+
logTestResult: typeof logTestResult
|
19
|
+
plan: typeof plan
|
20
|
+
setCameraTransform: typeof setCameraTransform
|
21
|
+
}
|
@@ -0,0 +1,11 @@
|
|
1
|
+
import type { Entity, LastWriteWinElementSetComponentDefinition } from '@dcl/ecs';
|
2
|
+
type Options = {
|
3
|
+
strict: boolean;
|
4
|
+
comp: typeof closeTo;
|
5
|
+
};
|
6
|
+
export declare function assertEquals(a: any, b: any, message?: string): void;
|
7
|
+
export declare function assert(a: any, message?: string): void;
|
8
|
+
export declare function assertComponentValue<T>(entity: Entity, component: LastWriteWinElementSetComponentDefinition<T>, value: T): void;
|
9
|
+
export declare function deepCloseTo(actual: any, expected: any, options?: Partial<Options>): boolean;
|
10
|
+
declare function closeTo(actual: any, expected: any, delta?: number): boolean;
|
11
|
+
export {};
|
@@ -0,0 +1,106 @@
|
|
1
|
+
const pSlice = Array.prototype.slice;
|
2
|
+
const floatEpsilon = 0.0000001;
|
3
|
+
export function assertEquals(a, b, message = 'Values are not equal') {
|
4
|
+
if (!deepCloseTo(a, b))
|
5
|
+
throw new Error(`${message} - ${JSON.stringify(a)} != ${JSON.stringify(b)}`);
|
6
|
+
}
|
7
|
+
export function assert(a, message = 'assertion failed') {
|
8
|
+
if (!a)
|
9
|
+
throw new Error(message);
|
10
|
+
}
|
11
|
+
export function assertComponentValue(entity, component, value) {
|
12
|
+
assert(component.has(entity), `The entity doesn't have a ${component.componentName} component`);
|
13
|
+
assertEquals(component.get(entity), value, `Invalid ${component.componentName} values`);
|
14
|
+
}
|
15
|
+
export function deepCloseTo(actual, expected, options = {}) {
|
16
|
+
const opts = Object.assign({}, { comp: closeTo }, options);
|
17
|
+
if (actual === expected) {
|
18
|
+
return true;
|
19
|
+
}
|
20
|
+
else if (actual instanceof Date && expected instanceof Date) {
|
21
|
+
return opts.comp(actual, expected);
|
22
|
+
}
|
23
|
+
else if (!actual || !expected || (typeof actual !== 'object' && typeof expected !== 'object')) {
|
24
|
+
if (opts.strict) {
|
25
|
+
if (!actual && !expected) {
|
26
|
+
return actual === expected;
|
27
|
+
}
|
28
|
+
if (typeof actual !== typeof expected) {
|
29
|
+
return false;
|
30
|
+
}
|
31
|
+
}
|
32
|
+
if (!actual && !expected) {
|
33
|
+
return actual === expected;
|
34
|
+
}
|
35
|
+
return opts.comp(actual, expected);
|
36
|
+
}
|
37
|
+
else {
|
38
|
+
return objEquiv(actual, expected, opts);
|
39
|
+
}
|
40
|
+
}
|
41
|
+
function isUndefinedOrNull(value) {
|
42
|
+
return value === null || value === undefined;
|
43
|
+
}
|
44
|
+
function isBuffer(x) {
|
45
|
+
if (!x || typeof x !== 'object' || typeof x.length !== 'number')
|
46
|
+
return false;
|
47
|
+
if (typeof x.copy !== 'function' || typeof x.slice !== 'function') {
|
48
|
+
return false;
|
49
|
+
}
|
50
|
+
if (x.length > 0 && typeof x[0] !== 'number')
|
51
|
+
return false;
|
52
|
+
return true;
|
53
|
+
}
|
54
|
+
function objEquiv(a, b, opts) {
|
55
|
+
let i, key;
|
56
|
+
if (isUndefinedOrNull(a) || isUndefinedOrNull(b))
|
57
|
+
return false;
|
58
|
+
if (a.prototype !== b.prototype)
|
59
|
+
return false;
|
60
|
+
if (isArguments(a)) {
|
61
|
+
if (!isArguments(b)) {
|
62
|
+
return false;
|
63
|
+
}
|
64
|
+
return deepCloseTo(pSlice.call(a), pSlice.call(b), opts);
|
65
|
+
}
|
66
|
+
if (isBuffer(a)) {
|
67
|
+
if (!isBuffer(b)) {
|
68
|
+
return false;
|
69
|
+
}
|
70
|
+
if (a.length !== b.length)
|
71
|
+
return false;
|
72
|
+
for (i = 0; i < a.length; i++) {
|
73
|
+
if (a[i] !== b[i])
|
74
|
+
return false;
|
75
|
+
}
|
76
|
+
return true;
|
77
|
+
}
|
78
|
+
try {
|
79
|
+
const ka = Object.keys(a);
|
80
|
+
const kb = Object.keys(b);
|
81
|
+
if (ka.length !== kb.length)
|
82
|
+
return false;
|
83
|
+
ka.sort();
|
84
|
+
kb.sort();
|
85
|
+
for (i = ka.length - 1; i >= 0; i--) {
|
86
|
+
if (ka[i] !== kb[i])
|
87
|
+
return false;
|
88
|
+
}
|
89
|
+
for (i = ka.length - 1; i >= 0; i--) {
|
90
|
+
key = ka[i];
|
91
|
+
if (!deepCloseTo(a[key], b[key], opts))
|
92
|
+
return false;
|
93
|
+
}
|
94
|
+
}
|
95
|
+
catch (e) {
|
96
|
+
return false;
|
97
|
+
}
|
98
|
+
return typeof a === typeof b;
|
99
|
+
}
|
100
|
+
function isArguments(object) {
|
101
|
+
return Object.prototype.toString.call(object) === '[object Arguments]';
|
102
|
+
}
|
103
|
+
function closeTo(actual, expected, delta = floatEpsilon) {
|
104
|
+
return Math.abs(actual - expected) < delta;
|
105
|
+
}
|
106
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXNzZXJ0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3Rlc3RpbmcvYXNzZXJ0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUlBLE1BQU0sTUFBTSxHQUFHLEtBQUssQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFBO0FBRXBDLE1BQU0sWUFBWSxHQUFHLFNBQVMsQ0FBQTtBQUk5QixNQUFNLFVBQVUsWUFBWSxDQUFDLENBQU0sRUFBRSxDQUFNLEVBQUUsVUFBa0Isc0JBQXNCO0lBQ25GLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUFFLE1BQU0sSUFBSSxLQUFLLENBQUMsR0FBRyxPQUFPLE1BQU0sSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsT0FBTyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQTtBQUN0RyxDQUFDO0FBRUQsTUFBTSxVQUFVLE1BQU0sQ0FBQyxDQUFNLEVBQUUsVUFBa0Isa0JBQWtCO0lBQ2pFLElBQUksQ0FBQyxDQUFDO1FBQUUsTUFBTSxJQUFJLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQTtBQUNsQyxDQUFDO0FBRUQsTUFBTSxVQUFVLG9CQUFvQixDQUNsQyxNQUFjLEVBQ2QsU0FBdUQsRUFDdkQsS0FBUTtJQUVSLE1BQU0sQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxFQUFFLDZCQUE2QixTQUFTLENBQUMsYUFBYSxZQUFZLENBQUMsQ0FBQTtJQUMvRixZQUFZLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUUsRUFBRSxLQUFLLEVBQUUsV0FBVyxTQUFTLENBQUMsYUFBYSxTQUFTLENBQUMsQ0FBQTtBQUMxRixDQUFDO0FBRUQsTUFBTSxVQUFVLFdBQVcsQ0FBQyxNQUFXLEVBQUUsUUFBYSxFQUFFLFVBQTRCLEVBQUU7SUFDcEYsTUFBTSxJQUFJLEdBQUcsTUFBTSxDQUFDLE1BQU0sQ0FBQyxFQUFFLEVB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QUFFRCxTQUFTLFdBQVcsQ0FBQyxNQUFXO0lBQzlCLE9BQU8sTUFBTSxDQUFDLFNBQVMsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLG9CQUFvQixDQUFBO0FBQ3hFLENBQUM7QUFDRCxTQUFTLE9BQU8sQ0FBQyxNQUFXLEVBQUUsUUFBYSxFQUFFLFFBQWdCLFlBQVk7SUFDdkUsT0FBTyxJQUFJLENBQUMsR0FBRyxDQUFDLE1BQU0sR0FBRyxRQUFRLENBQUMsR0FBRyxLQUFLLENBQUE7QUFDNUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIFZFUkJBVElNIENPUFkgT0YgaHR0cHM6Ly9naXRodWIuY29tL0xlbW9uUGkvZGVlcC1jbG9zZS10b1xuXG5pbXBvcnQgdHlwZSB7IEVudGl0eSwgTGFzdFdyaXRlV2luRWxlbWVudFNldENvbXBvbmVudERlZmluaXRpb24gfSBmcm9tICdAZGNsL2VjcydcblxuY29uc3QgcFNsaWNlID0gQXJyYXkucHJvdG90eXBlLnNsaWNlXG5cbmNvbnN0IGZsb2F0RXBzaWxvbiA9IDAuMDAwMDAwMVxuXG50eXBlIE9wdGlvbnMgPSB7IHN0cmljdDogYm9vbGVhbjsgY29tcDogdHlwZW9mIGNsb3NlVG8gfVxuXG5leHBvcnQgZnVuY3Rpb24gYXNzZXJ0RXF1YWxzKGE6IGFueSwgYjogYW55LCBtZXNzYWdlOiBzdHJpbmcgPSAnVmFsdWVzIGFyZSBub3QgZXF1YWwnKSB7XG4gIGlmICghZGVlcENsb3NlVG8oYSwgYikpIHRocm93IG5ldyBFcnJvcihgJHttZXNzYWdlfSAtICR7SlNPTi5zdHJpbmdpZnkoYSl9ICE9ICR7SlNPTi5zdHJpbmdpZnkoYil9YClcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGFzc2VydChhOiBhbnksIG1lc3NhZ2U6IHN0cmluZyA9ICdhc3NlcnRpb24gZmFpbGVkJykge1xuICBpZiAoIWEpIHRocm93IG5ldyBFcnJvcihtZXNzYWdlKVxufVxuXG5leHBvcnQgZnVuY3Rpb24gYXNzZXJ0Q29tcG9uZW50VmFsdWU8VD4oXG4gIGVudGl0eTogRW50aXR5LFxuICBjb21wb25lbnQ6IExhc3RXcml0ZVdpbkVsZW1lbnRTZXRDb21wb25lbnREZWZpbml0aW9uPFQ+LFxuICB2YWx1ZTogVFxuKSB7XG4gIGFzc2VydChjb21wb25lbnQuaGFzKGVudGl0eSksIGBUaGUgZW50aXR5IGRvZXNuJ3QgaGF2ZSBhICR7Y29tcG9uZW50LmNvbXBvbmVudE5hbWV9IGNvbXBvbmVudGApXG4gIGFzc2VydEVxdWFscyhjb21wb25lbnQuZ2V0KGVudGl0eSkhLCB2YWx1ZSwgYEludmFsaWQgJHtjb21wb25lbnQuY29tcG9uZW50TmFtZX0gdmFsdWVzYClcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGRlZXBDbG9zZVRvKGFjdHVhbDogYW55LCBleHBlY3RlZDogYW55LCBvcHRpb25zOiBQYXJ0aWFsPE9wdGlvbnM+ID0ge30pOiBib29sZWFuIHtcbiAgY29uc3Qgb3B0cyA9IE9iamVjdC5hc3NpZ24oe30sIHsgY29tcDogY2xvc2VUbyB9LCBvcHRpb25zKVxuICAvLyA3LjEuIEFsbCBpZGVudGljYWwgdmFsdWVzIGFyZSBlcXVpdmFsZW50LCBhcyBkZXRlcm1pbmVkIGJ5ID09PS5cbiAgaWYgKGFjdHVhbCA9PT0gZXhwZWN0ZWQpIHtcbiAgICByZXR1cm4gdHJ1ZVxuICB9IGVsc2UgaWYgKGFjdHVhbCBpbnN0YW5jZW9mIERhdGUgJiYgZXhwZWN0ZWQgaW5zdGFuY2VvZiBEYXRlKSB7XG4gICAgcmV0dXJuIG9wdHMuY29tcCEoYWN0dWFsLCBleHBlY3RlZClcblxuICAgIC8vIDcuMy4gT3RoZXIgcGFpcnMgdGhhdCBkbyBub3QgYm90aCBwYXNzIHR5cGVvZiB2YWx1ZSA9PSAnb2JqZWN0JyxcbiAgICAvLyBlcXVpdmFsZW5jZSBpcyBkZXRlcm1pbmVkIGJ5ID09LlxuICB9IGVsc2UgaWYgKCFhY3R1YWwgfHwgIWV4cGVjdGVkIHx8ICh0eXBlb2YgYWN0dWFsICE9PSAnb2JqZWN0JyAmJiB0eXBlb2YgZXhwZWN0ZWQgIT09ICdvYmplY3QnKSkge1xuICAgIGlmIChvcHRzLnN0cmljdCkge1xuICAgICAgaWYgKCFhY3R1YWwgJiYgIWV4cGVjdGVkKSB7XG4gICAgICAgIHJldHVybiBhY3R1YWwgPT09IGV4cGVjdGVkXG4gICAgICB9XG5cbiAgICAgIGlmICh0eXBlb2YgYWN0dWFsICE9PSB0eXBlb2YgZXhwZWN0ZWQpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlXG4gICAgICB9XG4gICAgfVxuICAgIGlmICghYWN0dWFsICYmICFleHBlY3RlZCkge1xuICAgICAgcmV0dXJuIGFjdHVhbCA9PT0gZXhwZWN0ZWRcbiAgICB9XG4gICAgcmV0dXJuIG9wdHMuY29tcCEoYWN0dWFsLCBleHBlY3RlZClcblxuICAgIC8vIDcuNC4gRm9yIGFsbCBvdGhlciBPYmplY3QgcGFpcnMsIGluY2x1ZGluZyBBcnJheSBvYmplY3RzLCBlcXVpdmFsZW5jZSBpc1xuICAgIC8vIGRldGVybWluZWQgYnkgaGF2aW5nIHRoZSBzYW1lIG51bWJlciBvZiBvd25lZCBwcm9wZXJ0aWVzIChhcyB2ZXJpZmllZFxuICAgIC8vIHdpdGggT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKSwgdGhlIHNhbWUgc2V0IG9mIGtleXNcbiAgICAvLyAoYWx0aG91Z2ggbm90IG5lY2Vzc2FyaWx5IHRoZSBzYW1lIG9yZGVyKSwgZXF1aXZhbGVudCB2YWx1ZXMgZm9yIGV2ZXJ5XG4gICAgLy8gY29ycmVzcG9uZGluZyBrZXksIGFuZCBhbiBpZGVudGljYWwgJ3Byb3RvdHlwZScgcHJvcGVydHkuIE5vdGU6IHRoaXNcbiAgICAvLyBhY2NvdW50cyBmb3IgYm90aCBuYW1lZCBhbmQgaW5kZXhlZCBwcm9wZXJ0aWVzIG9uIEFycmF5cy5cbiAgfSBlbHNlIHtcbiAgICByZXR1cm4gb2JqRXF1aXYoYWN0dWFsLCBleHBlY3RlZCwgb3B0cyBhcyBhbnkpXG4gIH1cbn1cblxuZnVuY3Rpb24gaXNVbmRlZmluZWRPck51bGwodmFsdWU6IGFueSkge1xuICByZXR1cm4gdmFsdWUgPT09IG51bGwgfHwgdmFsdWUgPT09IHVuZGVmaW5lZFxufVxuXG5mdW5jdGlvbiBpc0J1ZmZlcih4OiBhbnkpIHtcbiAgaWYgKCF4IHx8IHR5cGVvZiB4ICE9PSAnb2JqZWN0JyB8fCB0eXBlb2YgeC5sZW5ndGggIT09ICdudW1iZXInKSByZXR1cm4gZmFsc2VcbiAgaWYgKHR5cGVvZiB4LmNvcHkgIT09ICdmdW5jdGlvbicgfHwgdHlwZW9mIHguc2xpY2UgIT09ICdmdW5jdGlvbicpIHtcbiAgICByZXR1cm4gZmFsc2VcbiAgfVxuICBpZiAoeC5sZW5ndGggPiAwICYmIHR5cGVvZiB4WzBdICE9PSAnbnVtYmVyJykgcmV0dXJuIGZhbHNlXG4gIHJldHVybiB0cnVlXG59XG5cbmZ1bmN0aW9uIG9iakVxdWl2KGE6IGFueSwgYjogYW55LCBvcHRzOiBPcHRpb25zKSB7XG4gIGxldCBpLCBrZXlcbiAgaWYgKGlzVW5kZWZpbmVkT3JOdWxsKGEpIHx8IGlzVW5kZWZpbmVkT3JOdWxsKGIpKSByZXR1cm4gZmFsc2VcbiAgLy8gYW4gaWRlbnRpY2FsICdwcm90b3R5cGUnIHByb3BlcnR5LlxuICBpZiAoYS5wcm90b3R5cGUgIT09IGIucHJvdG90eXBlKSByZXR1cm4gZmFsc2VcbiAgLy9+fn5JJ3ZlIG1hbmFnZWQgdG8gYnJlYWsgT2JqZWN0LmtleXMgdGhyb3VnaCBzY3Jld3kgYXJndW1lbnRzIHBhc3NpbmcuXG4gIC8vICAgQ29udmVydGluZyB0byBhcnJheSBzb2x2ZXMgdGhlIHByb2JsZW0uXG4gIGlmIChpc0FyZ3VtZW50cyhhKSkge1xuICAgIGlmICghaXNBcmd1bWVudHMoYikpIHtcbiAgICAgIHJldHVybiBmYWxzZVxuICAgIH1cbiAgICByZXR1cm4gZGVlcENsb3NlVG8ocFNsaWNlLmNhbGwoYSksIHBTbGljZS5jYWxsKGIpLCBvcHRzKVxuICB9XG4gIGlmIChpc0J1ZmZlcihhKSkge1xuICAgIGlmICghaXNCdWZmZXIoYikpIHtcbiAgICAgIHJldHVybiBmYWxzZVxuICAgIH1cbiAgICBpZiAoYS5sZW5ndGggIT09IGIubGVuZ3RoKSByZXR1cm4gZmFsc2VcbiAgICBmb3IgKGkgPSAwOyBpIDwgYS5sZW5ndGg7IGkrKykge1xuICAgICAgaWYgKGFbaV0gIT09IGJbaV0pIHJldHVybiBmYWxzZVxuICAgIH1cbiAgICByZXR1cm4gdHJ1ZVxuICB9XG5cbiAgdHJ5IHtcbiAgICBjb25zdCBrYSA9IE9iamVjdC5rZXlzKGEpXG4gICAgY29uc3Qga2IgPSBPYmplY3Qua2V5cyhiKVxuXG4gICAgLy8gaGF2aW5nIHRoZSBzYW1lIG51bWJlciBvZiBvd25lZCBwcm9wZXJ0aWVzIChrZXlzIGluY29ycG9yYXRlc1xuICAgIC8vIGhhc093blByb3BlcnR5KVxuICAgIGlmIChrYS5sZW5ndGggIT09IGtiLmxlbmd0aCkgcmV0dXJuIGZhbHNlXG4gICAgLy90aGUgc2FtZSBzZXQgb2Yga2V5cyAoYWx0aG91Z2ggbm90IG5lY2Vzc2FyaWx5IHRoZSBzYW1lIG9yZGVyKSxcbiAgICBrYS5zb3J0KClcbiAgICBrYi5zb3J0KClcbiAgICAvL35+fmNoZWFwIGtleSB0ZXN0XG4gICAgZm9yIChpID0ga2EubGVuZ3RoIC0gMTsgaSA+PSAwOyBpLS0pIHtcbiAgICAgIGlmIChrYVtpXSAhPT0ga2JbaV0pIHJldHVybiBmYWxzZVxuICAgIH1cbiAgICAvL2VxdWl2YWxlbnQgdmFsdWVzIGZvciBldmVyeSBjb3JyZXNwb25kaW5nIGtleSwgYW5kXG4gICAgLy9+fn5wb3NzaWJseSBleHBlbnNpdmUgZGVlcCB0ZXN0XG4gICAgZm9yIChpID0ga2EubGVuZ3RoIC0gMTsgaSA+PSAwOyBpLS0pIHtcbiAgICAgIGtleSA9IGthW2ldXG4gICAgICBpZiAoIWRlZXBDbG9zZVRvKGFba2V5XSwgYltrZXldLCBvcHRzKSkgcmV0dXJuIGZhbHNlXG4gICAgfVxuICB9IGNhdGNoIChlKSB7XG4gICAgLy9oYXBwZW5zIHdoZW4gb25lIGlzIGEgc3RyaW5nIGxpdGVyYWwgYW5kIHRoZSBvdGhlciBpc24ndFxuICAgIHJldHVybiBmYWxzZVxuICB9XG5cbiAgcmV0dXJuIHR5cGVvZiBhID09PSB0eXBlb2YgYlxufVxuXG5mdW5jdGlvbiBpc0FyZ3VtZW50cyhvYmplY3Q6IGFueSkge1xuICByZXR1cm4gT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKG9iamVjdCkgPT09ICdbb2JqZWN0IEFyZ3VtZW50c10nXG59XG5mdW5jdGlvbiBjbG9zZVRvKGFjdHVhbDogYW55LCBleHBlY3RlZDogYW55LCBkZWx0YTogbnVtYmVyID0gZmxvYXRFcHNpbG9uKSB7XG4gIHJldHVybiBNYXRoLmFicyhhY3R1YWwgLSBleHBlY3RlZCkgPCBkZWx0YVxufVxuIl19
|
package/testing/index.js
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
import { engine } from '@dcl/ecs';
|
2
|
+
import { createTestRuntime } from './runtime';
|
3
|
+
export const test = DEBUG ? createTestFunction() : () => { };
|
4
|
+
function createTestFunction() {
|
5
|
+
let testingModule;
|
6
|
+
try {
|
7
|
+
testingModule = require('~system/Testing');
|
8
|
+
}
|
9
|
+
catch (err) {
|
10
|
+
console.error(err);
|
11
|
+
console.error(`🔴🚨‼️ WARNING: The test runner is not available. The test runner will be mocked. ‼️🚨🔴`);
|
12
|
+
testingModule = {
|
13
|
+
async logTestResult(data) {
|
14
|
+
console.log(`🧪 mocked '~system/Testing'.logResult`, data);
|
15
|
+
return {};
|
16
|
+
},
|
17
|
+
async plan(data) {
|
18
|
+
console.log(`🧪 mocked '~system/Testing'.plan`, data);
|
19
|
+
return {};
|
20
|
+
},
|
21
|
+
async setCameraTransform(transform) {
|
22
|
+
console.log(`🧪 mocked '~system/Testing'.setCameraTransform`, transform);
|
23
|
+
return {};
|
24
|
+
}
|
25
|
+
};
|
26
|
+
}
|
27
|
+
const runtime = createTestRuntime(testingModule, engine);
|
28
|
+
return runtime.test;
|
29
|
+
}
|
30
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvdGVzdGluZy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sVUFBVSxDQUFBO0FBQ2pDLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLFdBQVcsQ0FBQTtBQVc3QyxNQUFNLENBQUMsTUFBTSxJQUFJLEdBQTJCLEtBQUssQ0FBQyxDQUFDLENBQWlCLGtCQUFrQixFQUFFLENBQUMsQ0FBQyxDQUFpQixHQUFHLEVBQUUsR0FBRSxDQUFDLENBQUE7QUFFbkgsU0FBUyxrQkFBa0I7SUFDekIsSUFBSSxhQUE0QixDQUFBO0lBQ2hDLElBQUk7UUFDRixhQUFhLEdBQW1CLE9BQU8sQ0FBQyxpQkFBaUIsQ0FBQyxDQUFBO0tBQzNEO0lBQUMsT0FBTyxHQUFHLEVBQUU7UUFDWixPQUFPLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFBO1FBRWxCLE9BQU8sQ0FBQyxLQUFLLENBQUMsMEZBQTBGLENBQUMsQ0FBQTtRQUV6RyxhQUFhLEdBQUc7WUFDZCxLQUFLLENBQUMsYUFBYSxDQUFDLElBQUk7Z0JBQ3RCLE9BQU8sQ0FBQyxHQUFHLENBQUMsdUNBQXVDLEVBQUUsSUFBSSxDQUFDLENBQUE7Z0JBQzFELE9BQU8sRUFBRSxDQUFBO1lBQ1gsQ0FBQztZQUNELEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSTtnQkFDYixPQUFPLENBQUMsR0FBRyxDQUFDLGtDQUFrQyxFQUFFLElBQUksQ0FBQyxDQUFBO2dCQUNyRCxPQUFPLEVBQUUsQ0FBQTtZQUNYLENBQUM7WUFDRCxLQUFLLENBQUMsa0JBQWtCLENBQUMsU0FBUztnQkFDaEMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxnREFBZ0QsRUFBRSxTQUFTLENBQUMsQ0FBQTtnQkFDeEUsT0FBTyxFQUFFLENBQUE7WUFDWCxDQUFDO1NBQ0YsQ0FBQTtLQUNGO0lBRUQsTUFBTSxPQUFPLEdBQUcsaUJBQWlCLENBQUMsYUFBYSxFQUFFLE1BQU0sQ0FBQyxDQUFBO0lBQ3hELE9BQU8sT0FBTyxDQUFDLElBQUksQ0FBQTtBQUNyQixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgZW5naW5lIH0gZnJvbSAnQGRjbC9lY3MnXG5pbXBvcnQgeyBjcmVhdGVUZXN0UnVudGltZSB9IGZyb20gJy4vcnVudGltZSdcbmltcG9ydCB7IFRlc3REZWZpbml0aW9uRnVuY3Rpb24sIFRlc3RpbmdNb2R1bGUgfSBmcm9tICcuL3R5cGVzJ1xuXG5kZWNsYXJlIGxldCByZXF1aXJlOiBhbnlcblxuLyoqXG4gKiBJbiBkZXZlbG9wbWVudCBidWlsZHMsIHRoaXMgZnVuY3Rpb24gc2VydmVzIGFzIHRlc3QgcnVubmVyIGZvciBhdXRvbWF0ZWQgdGVzdCBzY2VuYXJpb3NcbiAqIGlmIHRoZSBydW50aW1lIGFjY2VwdHMgdGhlIGB+c3lzdGVtL1Rlc3RpbmdgIG1vZHVsZVxuICogQHB1YmxpY1xuICovXG4vKiBAX19QVVJFX18gKi9cbmV4cG9ydCBjb25zdCB0ZXN0OiBUZXN0RGVmaW5pdGlvbkZ1bmN0aW9uID0gREVCVUcgPyAvKiBAX19QVVJFX18gKi8gY3JlYXRlVGVzdEZ1bmN0aW9uKCkgOiAvKiBAX19QVVJFX18gKi8gKCkgPT4ge31cblxuZnVuY3Rpb24gY3JlYXRlVGVzdEZ1bmN0aW9uKCkge1xuICBsZXQgdGVzdGluZ01vZHVsZTogVGVzdGluZ01vZHVsZVxuICB0cnkge1xuICAgIHRlc3RpbmdNb2R1bGUgPSAvKiBAX19QVVJFX18gKi8gcmVxdWlyZSgnfnN5c3RlbS9UZXN0aW5nJylcbiAgfSBjYXRjaCAoZXJyKSB7XG4gICAgY29uc29sZS5lcnJvcihlcnIpXG5cbiAgICBjb25zb2xlLmVycm9yKGDwn5S08J+aqOKAvO+4jyBXQVJOSU5HOiBUaGUgdGVzdCBydW5uZXIgaXMgbm90IGF2YWlsYWJsZS4gVGhlIHRlc3QgcnVubmVyIHdpbGwgYmUgbW9ja2VkLiDigLzvuI/wn5qo8J+UtGApXG5cbiAgICB0ZXN0aW5nTW9kdWxlID0ge1xuICAgICAgYXN5bmMgbG9nVGVzdFJlc3VsdChkYXRhKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKGDwn6eqIG1vY2tlZCAnfnN5c3RlbS9UZXN0aW5nJy5sb2dSZXN1bHRgLCBkYXRhKVxuICAgICAgICByZXR1cm4ge31cbiAgICAgIH0sXG4gICAgICBhc3luYyBwbGFuKGRhdGEpIHtcbiAgICAgICAgY29uc29sZS5sb2coYPCfp6ogbW9ja2VkICd+c3lzdGVtL1Rlc3RpbmcnLnBsYW5gLCBkYXRhKVxuICAgICAgICByZXR1cm4ge31cbiAgICAgIH0sXG4gICAgICBhc3luYyBzZXRDYW1lcmFUcmFuc2Zvcm0odHJhbnNmb3JtKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKGDwn6eqIG1vY2tlZCAnfnN5c3RlbS9UZXN0aW5nJy5zZXRDYW1lcmFUcmFuc2Zvcm1gLCB0cmFuc2Zvcm0pXG4gICAgICAgIHJldHVybiB7fVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGNvbnN0IHJ1bnRpbWUgPSBjcmVhdGVUZXN0UnVudGltZSh0ZXN0aW5nTW9kdWxlLCBlbmdpbmUpXG4gIHJldHVybiBydW50aW1lLnRlc3Rcbn1cbiJdfQ==
|
@@ -0,0 +1,168 @@
|
|
1
|
+
import { Transform } from '@dcl/ecs';
|
2
|
+
import { assertEquals } from './assert';
|
3
|
+
export function createTestRuntime(testingModule, engine) {
|
4
|
+
let runtimeFrozen = false;
|
5
|
+
let currentFrameCounter = 0;
|
6
|
+
let currentFrameTime = 0;
|
7
|
+
const scheduledTests = [];
|
8
|
+
const nextTickFuture = [];
|
9
|
+
async function nextTick() {
|
10
|
+
return new Promise((resolve) => {
|
11
|
+
nextTickFuture.push(resolve);
|
12
|
+
});
|
13
|
+
}
|
14
|
+
engine.addSystem(function TestingFrameworkCoroutineRunner(dt) {
|
15
|
+
currentFrameCounter++;
|
16
|
+
currentFrameTime += dt;
|
17
|
+
nextTickFuture.splice(0, nextTickFuture.length).forEach((_) => _(dt));
|
18
|
+
});
|
19
|
+
function scheduleValue(value, env) {
|
20
|
+
if (value && typeof value === 'object' && typeof value.then === 'function') {
|
21
|
+
console.log('⏱️ yield promise');
|
22
|
+
nextTickFuture.push(async () => {
|
23
|
+
try {
|
24
|
+
scheduleValue(await value, env);
|
25
|
+
}
|
26
|
+
catch (err) {
|
27
|
+
env.reject(err);
|
28
|
+
}
|
29
|
+
});
|
30
|
+
}
|
31
|
+
else if (typeof value === 'function') {
|
32
|
+
console.log('⏱️ yield function');
|
33
|
+
nextTickFuture.push(() => {
|
34
|
+
scheduleValue(value(), env);
|
35
|
+
});
|
36
|
+
return;
|
37
|
+
}
|
38
|
+
else if (typeof value === 'undefined' || value === null) {
|
39
|
+
console.log('⏱️ yield');
|
40
|
+
nextTickFuture.push(() => {
|
41
|
+
consumeGenerator(env);
|
42
|
+
});
|
43
|
+
}
|
44
|
+
else
|
45
|
+
throw new Error(`Unexpected value from test generator: ${value}`);
|
46
|
+
}
|
47
|
+
function consumeGenerator(env) {
|
48
|
+
try {
|
49
|
+
const ret = env.generator.next();
|
50
|
+
if (!ret.done) {
|
51
|
+
scheduleValue(ret.value, env);
|
52
|
+
}
|
53
|
+
else {
|
54
|
+
env.resolve();
|
55
|
+
}
|
56
|
+
}
|
57
|
+
catch (err) {
|
58
|
+
env.reject(err);
|
59
|
+
}
|
60
|
+
}
|
61
|
+
function scheduleNextRun() {
|
62
|
+
if (scheduledTests.length) {
|
63
|
+
nextTickFuture.push(runTests);
|
64
|
+
}
|
65
|
+
}
|
66
|
+
function runTests() {
|
67
|
+
if (scheduledTests.length) {
|
68
|
+
const entry = scheduledTests.shift();
|
69
|
+
const initialFrame = currentFrameCounter;
|
70
|
+
const startTime = currentFrameTime;
|
71
|
+
let resolved = false;
|
72
|
+
const resolve = () => {
|
73
|
+
if (resolved)
|
74
|
+
throw new Error('resolved twice');
|
75
|
+
resolved = true;
|
76
|
+
console.log(`🟢 Test passed ${entry.name}`);
|
77
|
+
testingModule
|
78
|
+
.logTestResult({
|
79
|
+
name: entry.name,
|
80
|
+
ok: true,
|
81
|
+
totalFrames: currentFrameCounter - initialFrame,
|
82
|
+
totalTime: currentFrameTime - startTime
|
83
|
+
})
|
84
|
+
.finally(scheduleNextRun);
|
85
|
+
};
|
86
|
+
const reject = (err) => {
|
87
|
+
if (resolved)
|
88
|
+
throw new Error('resolved twice');
|
89
|
+
resolved = true;
|
90
|
+
console.log(`🔴 Test failed ${entry.name}`);
|
91
|
+
console.error(err);
|
92
|
+
testingModule
|
93
|
+
.logTestResult({
|
94
|
+
name: entry.name,
|
95
|
+
ok: false,
|
96
|
+
error: err.toString(),
|
97
|
+
stack: err && typeof err === 'object' && err.stack,
|
98
|
+
totalFrames: currentFrameCounter - initialFrame,
|
99
|
+
totalTime: currentFrameTime - startTime
|
100
|
+
})
|
101
|
+
.finally(scheduleNextRun);
|
102
|
+
};
|
103
|
+
try {
|
104
|
+
console.log(`🧪 Running test ${entry.name}`);
|
105
|
+
const testHelpers = {
|
106
|
+
async setCameraTransform(transform) {
|
107
|
+
await testingModule.setCameraTransform(transform);
|
108
|
+
await nextTick();
|
109
|
+
const TransformComponent = engine.getComponent(Transform.componentId);
|
110
|
+
const actualTransform = TransformComponent.get(engine.CameraEntity);
|
111
|
+
assertEquals(actualTransform.position, transform.position, "positions don't match");
|
112
|
+
assertEquals(actualTransform.rotation, transform.rotation, "rotations don't match");
|
113
|
+
}
|
114
|
+
};
|
115
|
+
const returnValue = entry.fn(testHelpers);
|
116
|
+
if (returnValue && typeof returnValue === 'object') {
|
117
|
+
if (isGenerator(returnValue)) {
|
118
|
+
const env = {
|
119
|
+
generator: returnValue,
|
120
|
+
helpers: testHelpers,
|
121
|
+
resolve,
|
122
|
+
reject
|
123
|
+
};
|
124
|
+
consumeGenerator(env);
|
125
|
+
}
|
126
|
+
else if (isPromise(returnValue)) {
|
127
|
+
returnValue.then(resolve).catch(reject);
|
128
|
+
}
|
129
|
+
else {
|
130
|
+
throw new Error(`Unknown test result type: ${returnValue}`);
|
131
|
+
}
|
132
|
+
}
|
133
|
+
else {
|
134
|
+
resolve();
|
135
|
+
}
|
136
|
+
}
|
137
|
+
catch (err) {
|
138
|
+
reject(err);
|
139
|
+
}
|
140
|
+
}
|
141
|
+
}
|
142
|
+
nextTickFuture.push(() => {
|
143
|
+
runtimeFrozen = true;
|
144
|
+
if (!scheduledTests.length)
|
145
|
+
return;
|
146
|
+
testingModule.plan({ tests: scheduledTests }).then(scheduleNextRun).catch(globalFail);
|
147
|
+
});
|
148
|
+
function test(name, fn) {
|
149
|
+
if (runtimeFrozen)
|
150
|
+
throw new Error("New tests can't be added at this stage.");
|
151
|
+
if (scheduledTests.some(($) => $.name === name))
|
152
|
+
throw new Error(`Test with name ${name} already exists`);
|
153
|
+
scheduledTests.push({ fn, name });
|
154
|
+
}
|
155
|
+
return {
|
156
|
+
test
|
157
|
+
};
|
158
|
+
}
|
159
|
+
function isGenerator(t) {
|
160
|
+
return t && typeof t === 'object' && typeof t[Symbol.iterator] === 'function';
|
161
|
+
}
|
162
|
+
function isPromise(t) {
|
163
|
+
return t && typeof t === 'object' && typeof t.then === 'function';
|
164
|
+
}
|
165
|
+
function globalFail(error) {
|
166
|
+
console.error(error);
|
167
|
+
}
|
168
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnVudGltZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy90ZXN0aW5nL3J1bnRpbWUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBSUEsT0FBTyxFQUFXLFNBQVMsRUFBRSxNQUFNLFVBQVUsQ0FBQTtBQUM3QyxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sVUFBVSxDQUFBO0FBT3ZDLE1BQU0sVUFBVSxpQkFBaUIsQ0FBQyxhQUE0QixFQUFFLE1BQWU7SUFVN0UsSUFBSSxhQUFhLEdBQUcsS0FBSyxDQUFBO0lBRXpCLElBQUksbUJBQW1CLEdBQUcsQ0FBQyxDQUFBO0lBQzNCLElBQUksZ0JBQWdCLEdBQUcsQ0FBQyxDQUFBO0lBR3hCLE1BQU0sY0FBYyxHQUFvQixFQUFFLENBQUE7SUFHMUMsTUFBTSxjQUFjLEdBQWdDLEVBQUUsQ0FBQTtJQUd0RCxLQUFLLFVBQVUsUUFBUTtRQUNyQixPQUFPLElBQUksT0FBTyxDQUFTLENBQUMsT0FBTyxFQUFFLEVBQUU7WUFDckMsY0FBYyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQTtRQUM5QixDQUFDLENBQUMsQ0FBQTtJQUNKLENBQUM7SUFHRCxNQUFNLENBQUMsU0FBUyxDQUFDLFNBQVMsK0JBQStCLENBQUMsRUFBRTtRQUMxRCxtQkFBbUIsRUFBRSxDQUFBO1FBQ3JCLGdCQUFnQixJQUFJLEVBQUUsQ0FBQTtRQUV0QixjQUFjLENBQUMsTUFBTSxDQUFDLENBQUMsRUFBRSxjQUFjLENBQUMsTUFBTSxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQTtJQUN2RSxDQUFDLENBQUMsQ0FBQTtJQUlGLFNBQVMsYUFBYSxDQUFDLEtBQVUsRUFBRSxHQUFzQjtRQUN2RCxJQUFJLEtBQUssSUFBSSxPQUFPLEtBQUssS0FBSyxRQUFRLElBQUksT0FBTyxLQUFLLENBQUMsSUFBSSxLQUFLLFVBQVUsRUFBRTtZ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YTtZQUFFLE1BQU0sSUFBSSxLQUFLLENBQUMseUNBQXlDLENBQUMsQ0FBQTtRQUU3RSxJQUFJLGNBQWMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLEtBQUssSUFBSSxDQUFDO1lBQUUsTUFBTSxJQUFJLEtBQUssQ0FBQyxrQkFBa0IsSUFBSSxpQkFBaUIsQ0FBQyxDQUFBO1FBRXpHLGNBQWMsQ0FBQyxJQUFJLENBQUMsRUFBRSxFQUFFLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQTtJQUNuQyxDQUFDO0lBRUQsT0FBTztRQUNMLElBQUk7S0FDTCxDQUFBO0FBQ0gsQ0FBQztBQUVELFNBQVMsV0FBVyxDQUFDLENBQU07SUFDekIsT0FBTyxDQUFDLElBQUksT0FBTyxDQUFDLEtBQUssUUFBUSxJQUFJLE9BQU8sQ0FBQyxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsS0FBSyxVQUFVLENBQUE7QUFDL0UsQ0FBQztBQUVELFNBQVMsU0FBUyxDQUFDLENBQU07SUFDdkIsT0FBTyxDQUFDLElBQUksT0FBTyxDQUFDLEtBQUssUUFBUSxJQUFJLE9BQU8sQ0FBQyxDQUFDLElBQUksS0FBSyxVQUFVLENBQUE7QUFDbkUsQ0FBQztBQUVELFNBQVMsVUFBVSxDQUFDLEtBQVU7SUFFNUIsT0FBTyxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQTtBQUN0QixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBUaGlzIG1vZHVsZSBwcm92aWRlcyBhIGNyZWF0ZVRlc3RSdW50aW1lIGZ1bmN0aW9uIHRoYXQgcmV0dXJucyBhbiBvYmplY3Qgd2l0aCBhIHRlc3QgZnVuY3Rpb24gdGhhdCBjYW4gYmUgdXNlZCB0byBkZWZpbmUgdGVzdHMuXG4gKi9cblxuaW1wb3J0IHsgSUVuZ2luZSwgVHJhbnNmb3JtIH0gZnJvbSAnQGRjbC9lY3MnXG5pbXBvcnQgeyBhc3NlcnRFcXVhbHMgfSBmcm9tICcuL2Fzc2VydCdcbmltcG9ydCB0eXBlIHsgVGVzdGluZ01vZHVsZSwgVGVzdEZ1bmN0aW9uLCBUZXN0SGVscGVycyB9IGZyb20gJy4vdHlwZXMnXG5cbi8vIFRoaXMgZnVuY3Rpb24gY3JlYXRlcyBhIHRlc3QgcnVudGltZSB0aGF0IGNhbiBiZSB1c2VkIHRvIGRlZmluZSBhbmQgcnVuIHRlc3RzLlxuLy8gSXQgdGFrZXMgYSBgVGVzdGluZ01vZHVsZWAgaW5zdGFuY2UgKGxvYWRlZCBmcm9tIHJlcXVpcmUoJ35zeXN0ZW0vVGVzdGluZycpKSBhbmQgYW4gYElFbmdpbmVgIGluc3RhbmNlIChmcm9tIERlY2VudHJhbGFuZCdzIFNESykuXG4vLyBJdCByZXR1cm5zIGFuIG9iamVjdCB3aXRoIGEgYHRlc3RgIGZ1bmN0aW9uIHRoYXQgY2FuIGJlIHVzZWQgdG8gZGVmaW5lIHRlc3RzLlxuLyogQF9fUFVSRV9fICovXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlVGVzdFJ1bnRpbWUodGVzdGluZ01vZHVsZTogVGVzdGluZ01vZHVsZSwgZW5naW5lOiBJRW5naW5lKSB7XG4gIHR5cGUgVGVzdFBsYW5FbnRyeSA9IHsgbmFtZTogc3RyaW5nOyBmbjogVGVzdEZ1bmN0aW9uIH1cbiAgdHlwZSBSdW5uZXJFbnZpcm9ubWVudCA9IHtcbiAgICByZXNvbHZlOiAoKSA9PiB2b2lkXG4gICAgcmVqZWN0OiAoZXJyb3I6IGFueSkgPT4gdm9pZFxuICAgIGhlbHBlcnM6IFRlc3RIZWxwZXJzXG4gICAgZ2VuZXJhdG9yOiBHZW5lcmF0b3JcbiAgfVxuXG4gIC8vIHRoaXMgZmxhZyBlbnN1cmVzIG5vIHRlc3RzIGFyZSBhZGRlZCBhc3luY2hyb25vdXNseVxuICBsZXQgcnVudGltZUZyb3plbiA9IGZhbHNlXG5cbiAgbGV0IGN1cnJlbnRGcmFtZUNvdW50ZXIgPSAwXG4gIGxldCBjdXJyZW50RnJhbWVUaW1lID0gMFxuXG4gIC8vIGFycmF5IHRvIGhvbGQgdGhlIHNjaGVkdWxlZCB0ZXN0c1xuICBjb25zdCBzY2hlZHVsZWRUZXN0czogVGVzdFBsYW5FbnRyeVtdID0gW11cblxuICAvLyBhbiBhcnJheSBvZiBwcm9taXNlcyB0aGF0IGFyZSByZXNvbHZlZCBvbiB0aGUgbmV4dCBmcmFtZSAoYWZ0ZXIgdGhlIGN1cnJlbnQgZnJhbWUgaXMgZmluaXNoZWQpXG4gIGNvbnN0IG5leHRUaWNrRnV0dXJlOiBBcnJheTwoZHQ6IG51bWJlcikgPT4gdm9pZD4gPSBbXVxuXG4gIC8vIHRoaXMgZnVuY3Rpb24gcmV0dXJucyBhIHByb21pc2UgdGhhdCByZXNvbHZlcyBvbiB0aGUgbmV4dCBmcmFtZVxuICBhc3luYyBmdW5jdGlvbiBuZXh0VGljaygpIHtcbiAgICByZXR1cm4gbmV3IFByb21pc2U8bnVtYmVyPigocmVzb2x2ZSkgPT4ge1xuICAgICAgbmV4dFRpY2tGdXR1cmUucHVzaChyZXNvbHZlKVxuICAgIH0pXG4gIH1cblxuICAvLyBhZGQgYSBzeXN0ZW0gdG8gdGhlIGVuZ2luZSB0aGF0IHJlc29sdmVzIGFsbCBwcm9taXNlcyBpbiB0aGUgYG5leHRUaWNrRnV0dXJlYCBhcnJheVxuICBlbmdpbmUuYWRkU3lzdGVtKGZ1bmN0aW9uIFRlc3RpbmdGcmFtZXdvcmtDb3JvdXRpbmVSdW5uZXIoZHQpIHtcbiAgICBjdXJyZW50RnJhbWVDb3VudGVyKytcbiAgICBjdXJyZW50RnJhbWVUaW1lICs9IGR0XG4gICAgLy8gcmVzb2x2ZSBhbGwgbmV4dFRpY2sgZnV0dXJlcy5cbiAgICBuZXh0VGlja0Z1dHVyZS5zcGxpY2UoMCwgbmV4dFRpY2tGdXR1cmUubGVuZ3RoKS5mb3JFYWNoKChfKSA9PiBfKGR0KSlcbiAgfSlcblxuICAvLyB0aGlzIGZ1bmN0aW9uIHNjaGVkdWxlcyBhIHZhbHVlIHRvIGJlIHByb2Nlc3NlZCBvbiB0aGUgbmV4dCBmcmFtZSwgdGhlIHRlc3QgcnVubmVyIHdpbGxcbiAgLy8gY29udGludWUgdG8gcnVuIHVudGlsIGl0IHJlYWNoZXMgYSB5aWVsZCBwb2ludFxuICBmdW5jdGlvbiBzY2hlZHVsZVZhbHVlKHZhbHVlOiBhbnksIGVudjogUnVubmVyRW52aXJvbm1lbnQpIHtcbiAgICBpZiAodmFsdWUgJiYgdHlwZW9mIHZhbHVlID09PSAnb2JqZWN0JyAmJiB0eXBlb2YgdmFsdWUudGhlbiA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgY29uc29sZS5sb2coJ+KPse+4jyB5aWVsZCBwcm9taXNlJylcbiAgICAgIC8vIGlmIHRoZSB2YWx1ZSBpcyBhIHByb21pc2UsIHNjaGVkdWxlIGl0IHRvIGJlIGF3YWl0ZWQgYWZ0ZXIgdGhlIGN1cnJlbnQgZnJhbWUgaXMgZmluaXNoZWRcbiAgICAgIG5leHRUaWNrRnV0dXJlLnB1c2goYXN5bmMgKCkgPT4ge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIHNjaGVkdWxlVmFsdWUoYXdhaXQgdmFsdWUsIGVudilcbiAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgZW52LnJlamVjdChlcnIpXG4gICAgICAgIH1cbiAgICAgIH0pXG4gICAgfSBlbHNlIGlmICh0eXBlb2YgdmFsdWUgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgIGNvbnNvbGUubG9nKCfij7HvuI8geWllbGQgZnVuY3Rpb24nKVxuICAgICAgLy8gaWYgdGhlIHZhbHVlIGlzIGEgZnVuY3Rpb24sIHNjaGVkdWxlIGl0IHRvIGJlIGNhbGxlZCBvbiB0aGUgbmV4dCBmcmFtZVxuICAgICAgbmV4dFRpY2tGdXR1cmUucHVzaCgoKSA9PiB7XG4gICAgICAgIHNjaGVkdWxlVmFsdWUodmFsdWUoKSwgZW52KVxuICAgICAgfSlcbiAgICAgIHJldHVyblxuICAgIH0gZWxzZSBpZiAodHlwZW9mIHZhbHVlID09PSAndW5kZWZpbmVkJyB8fCB2YWx1ZSA9PT0gbnVsbCkge1xuICAgICAgY29uc29sZS5sb2coJ+KPse+4jyB5aWVsZCcpXG4gICAgICAvLyBpZiB0aGUgdmFsdWUgaXMgdW5kZWZpbmVkIG9yIG51bGwsIGNvbnRpbnVlIHByb2Nlc3NpbmcgdGhlIGdlbmVyYXRvciB0aGUgbmV4dCBmcmFtZVxuICAgICAgbmV4dFRpY2tGdXR1cmUucHVzaCgoKSA9PiB7XG4gICAgICAgIGNvbnN1bWVHZW5lcmF0b3IoZW52KVxuICAgICAgfSlcbiAgICB9IGVsc2UgdGhyb3cgbmV3IEVycm9yKGBVbmV4cGVjdGVkIHZhbHVlIGZyb20gdGVzdCBnZW5lcmF0b3I6ICR7dmFsdWV9YClcbiAgfVxuXG4gIC8vIHRoaXMgZnVuY3Rpb24gcHJvY2Vzc2VzIGEgZ2VuZXJhdG9yIGZ1bmN0aW9uIGJ5IHNjaGVkdWxpbmcgaXRzIHZhbHVlcyB0byBiZSBwcm9jZXNzZWQgb24gdGhlIG5leHQgZnJhbWVcbiAgZnVuY3Rpb24gY29uc3VtZUdlbmVyYXRvcihlbnY6IFJ1bm5lckVudmlyb25tZW50KSB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHJldCA9IGVudi5nZW5lcmF0b3IubmV4dCgpXG4gICAgICBpZiAoIXJldC5kb25lKSB7XG4gICAgICAgIHNjaGVkdWxlVmFsdWUocmV0LnZhbHVlLCBlbnYpXG4gICAgICB9IGVsc2Uge1xuICAgICAgICBlbnYucmVzb2x2ZSgpXG4gICAgICB9XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICBlbnYucmVqZWN0KGVycilcbiAgICB9XG4gIH1cblxuICAvLyB0aGlzIGZ1bmN0aW9uIHNjaGVkdWxlcyBhIHRlc3QgcnVuIG9uIHRoZSBuZXh0IGZyYW1lXG4gIGZ1bmN0aW9uIHNjaGVkdWxlTmV4dFJ1bigpIHtcbiAgICBpZiAoc2NoZWR1bGVkVGVzdHMubGVuZ3RoKSB7XG4gICAgICBuZXh0VGlja0Z1dHVyZS5wdXNoKHJ1blRlc3RzKVxuICAgIH1cbiAgfVxuXG4gIC8vIHRoaXMgZnVuY3Rpb24gcnVucyB0aGUgc2NoZWR1bGVkIHRlc3RzXG4gIGZ1bmN0aW9uIHJ1blRlc3RzKCkge1xuICAgIGlmIChzY2hlZHVsZWRUZXN0cy5sZW5ndGgpIHtcbiAgICAgIGNvbnN0IGVudHJ5ID0gc2NoZWR1bGVkVGVzdHMuc2hpZnQoKSFcbiAgICAgIGNvbnN0IGluaXRpYWxGcmFtZSA9IGN1cnJlbnRGcmFtZUNvdW50ZXJcbiAgICAgIGNvbnN0IHN0YXJ0VGltZSA9IGN1cnJlbnRGcmFtZVRpbWVcblxuICAgICAgbGV0IHJlc29sdmVkID0gZmFsc2VcblxuICAgICAgLy8gdGhpcyBmdW5jdGlvbiBzaG91bGQgYmUgY2FsbGVkIG9ubHkgb25jZS4gaXQgbWFrZXMgdGhlIGN1cnJlbnQgdGVzdCBwYXNzXG4gICAgICBjb25zdCByZXNvbHZlID0gKCkgPT4ge1xuICAgICAgICBpZiAocmVzb2x2ZWQpIHRocm93IG5ldyBFcnJvcigncmVzb2x2ZWQgdHdpY2UnKVxuICAgICAgICByZXNvbHZlZCA9IHRydWVcblxuICAgICAgICBjb25zb2xlLmxvZyhg8J+foiBUZXN0IHBhc3NlZCAke2VudHJ5Lm5hbWV9YClcblxuICAgICAgICB0ZXN0aW5nTW9kdWxlXG4gICAgICAgICAgLmxvZ1Rlc3RSZXN1bHQoe1xuICAgICAgICAgICAgbmFtZTogZW50cnkubmFtZSxcbiAgICAgICAgICAgIG9rOiB0cnVlLFxuICAgICAgICAgICAgdG90YWxGcmFtZXM6IGN1cnJlbnRGcmFtZUNvdW50ZXIgLSBpbml0aWFsRnJhbWUsXG4gICAgICAgICAgICB0b3RhbFRpbWU6IGN1cnJlbnRGcmFtZVRpbWUgLSBzdGFydFRpbWVcbiAgICAgICAgICB9KVxuICAgICAgICAgIC5maW5hbGx5KHNjaGVkdWxlTmV4dFJ1bilcbiAgICAgIH1cblxuICAgICAgY29uc3QgcmVqZWN0ID0gKGVycjogYW55KSA9PiB7XG4gICAgICAgIGlmIChyZXNvbHZlZCkgdGhyb3cgbmV3IEVycm9yKCdyZXNvbHZlZCB0d2ljZScpXG4gICAgICAgIHJlc29sdmVkID0gdHJ1ZVxuXG4gICAgICAgIGNvbnNvbGUubG9nKGDwn5S0IFRlc3QgZmFpbGVkICR7ZW50cnkubmFtZX1gKVxuICAgICAgICBjb25zb2xlLmVycm9yKGVycilcblxuICAgICAgICB0ZXN0aW5nTW9kdWxlXG4gICAgICAgICAgLmxvZ1Rlc3RSZXN1bHQoe1xuICAgICAgICAgICAgbmFtZTogZW50cnkubmFtZSxcbiAgICAgICAgICAgIG9rOiBmYWxzZSxcbiAgICAgICAgICAgIGVycm9yOiBlcnIudG9TdHJpbmcoKSxcbiAgICAgICAgICAgIHN0YWNrOiBlcnIgJiYgdHlwZW9mIGVyciA9PT0gJ29iamVjdCcgJiYgZXJyLnN0YWNrLFxuICAgICAgICAgICAgdG90YWxGcmFtZXM6IGN1cnJlbnRGcmFtZUNvdW50ZXIgLSBpbml0aWFsRnJhbWUsXG4gICAgICAgICAgICB0b3RhbFRpbWU6IGN1cnJlbnRGcmFtZVRpbWUgLSBzdGFydFRpbWVcbiAgICAgICAgICB9KVxuICAgICAgICAgIC5maW5hbGx5KHNjaGVkdWxlTmV4dFJ1bilcbiAgICAgIH1cblxuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc29sZS5sb2coYPCfp6ogUnVubmluZyB0ZXN0ICR7ZW50cnkubmFtZX1gKVxuXG4gICAgICAgIGNvbnN0IHRlc3RIZWxwZXJzOiBUZXN0SGVscGVycyA9IHtcbiAgICAgICAgICBhc3luYyBzZXRDYW1lcmFUcmFuc2Zvcm0odHJhbnNmb3JtKSB7XG4gICAgICAgICAgICBhd2FpdCB0ZXN0aW5nTW9kdWxlLnNldENhbWVyYVRyYW5zZm9ybSh0cmFuc2Zvcm0pXG4gICAgICAgICAgICBhd2FpdCBuZXh0VGljaygpXG5cbiAgICAgICAgICAgIGNvbnN0IFRyYW5zZm9ybUNvbXBvbmVudCA9IGVuZ2luZS5nZXRDb21wb25lbnQoVHJhbnNmb3JtLmNvbXBvbmVudElkKSBhcyB0eXBlb2YgVHJhbnNmb3JtXG4gICAgICAgICAgICBjb25zdCBhY3R1YWxUcmFuc2Zvcm0gPSBUcmFuc2Zvcm1Db21wb25lbnQuZ2V0KGVuZ2luZS5DYW1lcmFFbnRpdHkpXG5cbiAgICAgICAgICAgIGFzc2VydEVxdWFscyhhY3R1YWxUcmFuc2Zvcm0ucG9zaXRpb24sIHRyYW5zZm9ybS5wb3NpdGlvbiwgXCJwb3NpdGlvbnMgZG9uJ3QgbWF0Y2hcIilcbiAgICAgICAgICAgIGFzc2VydEVxdWFscyhhY3R1YWxUcmFuc2Zvcm0ucm90YXRpb24sIHRyYW5zZm9ybS5yb3RhdGlvbiwgXCJyb3RhdGlvbnMgZG9uJ3QgbWF0Y2hcIilcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCByZXR1cm5WYWx1ZSA9IGVudHJ5LmZuKHRlc3RIZWxwZXJzKVxuXG4gICAgICAgIGlmIChyZXR1cm5WYWx1ZSAmJiB0eXBlb2YgcmV0dXJuVmFsdWUgPT09ICdvYmplY3QnKSB7XG4gICAgICAgICAgaWYgKGlzR2VuZXJhdG9yKHJldHVyblZhbHVlKSkge1xuICAgICAgICAgICAgY29uc3QgZW52OiBSdW5uZXJFbnZpcm9ubWVudCA9IHtcbiAgICAgICAgICAgICAgZ2VuZXJhdG9yOiByZXR1cm5WYWx1ZSxcbiAgICAgICAgICAgICAgaGVscGVyczogdGVzdEhlbHBlcnMsXG4gICAgICAgICAgICAgIHJlc29sdmUsXG4gICAgICAgICAgICAgIHJlamVjdFxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY29uc3VtZUdlbmVyYXRvcihlbnYpXG4gICAgICAgICAgfSBlbHNlIGlmIChpc1Byb21pc2UocmV0dXJuVmFsdWUpKSB7XG4gICAgICAgICAgICByZXR1cm5WYWx1ZS50aGVuKHJlc29sdmUpLmNhdGNoKHJlamVjdClcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBVbmtub3duIHRlc3QgcmVzdWx0IHR5cGU6ICR7cmV0dXJuVmFsdWV9YClcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgcmVzb2x2ZSgpXG4gICAgICAgIH1cbiAgICAgIH0gY2F0Y2ggKGVycjogYW55KSB7XG4gICAgICAgIHJlamVjdChlcnIpXG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLy8gc2NoZWR1bGUgdGhlIHRlc3QgcnVubmVyIHN0YXJ0IGZvciB0aGUgbmV4dCBmcmFtZVxuICBuZXh0VGlja0Z1dHVyZS5wdXNoKCgpID0+IHtcbiAgICAvLyBvbmNlIHdlIHJ1biB0aGUgbmV4dCB0aWNrLCB0aGUgdGVzdCBydW50aW1lIGJlY29tZXMgZnJvemVuLiB0aGF0IG1lYW5zIG5vIG5ld1xuICAgIC8vIHRlc3QgZGVmaW5pdGlvbnMgYXJlIGFjY2VwdGVkXG4gICAgcnVudGltZUZyb3plbiA9IHRydWVcblxuICAgIGlmICghc2NoZWR1bGVkVGVzdHMubGVuZ3RoKSByZXR1cm5cblxuICAgIC8vIGluZm9ybSB0aGUgdGVzdCBydW5uZXIgYWJvdXQgdGhlIHBsYW5zIGZvciB0aGlzIHRlc3QgcnVuXG4gICAgdGVzdGluZ01vZHVsZS5wbGFuKHsgdGVzdHM6IHNjaGVkdWxlZFRlc3RzIH0pLnRoZW4oc2NoZWR1bGVOZXh0UnVuKS5jYXRjaChnbG9iYWxGYWlsKVxuICB9KVxuXG4gIC8vIHRoaXMgaXMgdGhlIGZ1bmN0aW9uIHRoYXQgaXMgdXNlZCB0byBwbGFuIGEgdGVzdCBmdW5jdGlvbm5cbiAgLyogQF9fUFVSRV9fICovXG4gIGZ1bmN0aW9uIHRlc3QobmFtZTogc3RyaW5nLCBmbjogVGVzdEZ1bmN0aW9uKSB7XG4gICAgaWYgKHJ1bnRpbWVGcm96ZW4pIHRocm93IG5ldyBFcnJvcihcIk5ldyB0ZXN0cyBjYW4ndCBiZSBhZGRlZCBhdCB0aGlzIHN0YWdlLlwiKVxuXG4gICAgaWYgKHNjaGVkdWxlZFRlc3RzLnNvbWUoKCQpID0+ICQubmFtZSA9PT0gbmFtZSkpIHRocm93IG5ldyBFcnJvcihgVGVzdCB3aXRoIG5hbWUgJHtuYW1lfSBhbHJlYWR5IGV4aXN0c2ApXG5cbiAgICBzY2hlZHVsZWRUZXN0cy5wdXNoKHsgZm4sIG5hbWUgfSlcbiAgfVxuXG4gIHJldHVybiB7XG4gICAgdGVzdFxuICB9XG59XG5cbmZ1bmN0aW9uIGlzR2VuZXJhdG9yKHQ6IGFueSk6IHQgaXMgR2VuZXJhdG9yIHtcbiAgcmV0dXJuIHQgJiYgdHlwZW9mIHQgPT09ICdvYmplY3QnICYmIHR5cGVvZiB0W1N5bWJvbC5pdGVyYXRvcl0gPT09ICdmdW5jdGlvbidcbn1cblxuZnVuY3Rpb24gaXNQcm9taXNlKHQ6IGFueSk6IHQgaXMgUHJvbWlzZTx1bmtub3duPiB7XG4gIHJldHVybiB0ICYmIHR5cGVvZiB0ID09PSAnb2JqZWN0JyAmJiB0eXBlb2YgdC50aGVuID09PSAnZnVuY3Rpb24nXG59XG5cbmZ1bmN0aW9uIGdsb2JhbEZhaWwoZXJyb3I6IGFueSkge1xuICAvLyBmb3Igbm93LCB0aGUgZmFpbHVyZSBpcyBvbmx5IHdyaXRpbmcgdG8gdGhlIGNvbnNvbGUuZXJyb3IuXG4gIGNvbnNvbGUuZXJyb3IoZXJyb3IpXG59XG4iXX0=
|
@@ -0,0 +1,13 @@
|
|
1
|
+
/// <reference types="@dcl/js-runtime" />
|
2
|
+
import type { TransformType } from '@dcl/ecs';
|
3
|
+
import type { logTestResult, plan, setCameraTransform } from '~system/Testing';
|
4
|
+
export type TestHelpers = {
|
5
|
+
setCameraTransform(transform: Pick<TransformType, 'position' | 'rotation'>): Promise<void>;
|
6
|
+
};
|
7
|
+
export type TestFunction = (helpers: TestHelpers) => Generator | Promise<any>;
|
8
|
+
export type TestDefinitionFunction = (name: string, fn: TestFunction) => void;
|
9
|
+
export type TestingModule = {
|
10
|
+
logTestResult: typeof logTestResult;
|
11
|
+
plan: typeof plan;
|
12
|
+
setCameraTransform: typeof setCameraTransform;
|
13
|
+
};
|
package/testing/types.js
ADDED
@@ -0,0 +1,2 @@
|
|
1
|
+
export {};
|
2
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvdGVzdGluZy90eXBlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHR5cGUgeyBUcmFuc2Zvcm1UeXBlIH0gZnJvbSAnQGRjbC9lY3MnXG5pbXBvcnQgdHlwZSB7IGxvZ1Rlc3RSZXN1bHQsIHBsYW4sIHNldENhbWVyYVRyYW5zZm9ybSB9IGZyb20gJ35zeXN0ZW0vVGVzdGluZydcblxuZXhwb3J0IHR5cGUgVGVzdEhlbHBlcnMgPSB7XG4gIC8qKlxuICAgKiBJbnN0cnVjdHMgdGhlIHJlbmRlcmVyIHRvIHNldCB0aGUgY2FtZXJhIHRyYW5zZm9ybSB0byB0aGUgcHJvdmlkZWQgYXJndW1lbnQuXG4gICAqIFRoaXMgZnVuY3Rpb24gcmVzb2x2ZXMgdGhlIG5leHQgZnJhbWUgYW5kIGZhaWxzIGlmIHRoZSBDYW1lcmFUcmFuc2Zvcm0gaXMgbm90XG4gICAqIGVxdWFsIHRvIHRoZSBwcm92aWRlZCBhcmd1bWVudC5cbiAgICovXG4gIHNldENhbWVyYVRyYW5zZm9ybSh0cmFuc2Zvcm06IFBpY2s8VHJhbnNmb3JtVHlwZSwgJ3Bvc2l0aW9uJyB8ICdyb3RhdGlvbic+KTogUHJvbWlzZTx2b2lkPlxufVxuXG5leHBvcnQgdHlwZSBUZXN0RnVuY3Rpb24gPSAoaGVscGVyczogVGVzdEhlbHBlcnMpID0+IEdlbmVyYXRvciB8IFByb21pc2U8YW55PlxuXG5leHBvcnQgdHlwZSBUZXN0RGVmaW5pdGlvbkZ1bmN0aW9uID0gKG5hbWU6IHN0cmluZywgZm46IFRlc3RGdW5jdGlvbikgPT4gdm9pZFxuXG5leHBvcnQgdHlwZSBUZXN0aW5nTW9kdWxlID0ge1xuICBsb2dUZXN0UmVzdWx0OiB0eXBlb2YgbG9nVGVzdFJlc3VsdFxuICBwbGFuOiB0eXBlb2YgcGxhblxuICBzZXRDYW1lcmFUcmFuc2Zvcm06IHR5cGVvZiBzZXRDYW1lcmFUcmFuc2Zvcm1cbn1cbiJdfQ==
|
package/README.md
DELETED
File without changes
|
package/tsconfig.cli.json
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
{
|
2
|
-
"compilerOptions": {
|
3
|
-
"target": "ES2017",
|
4
|
-
"module": "commonjs",
|
5
|
-
"esModuleInterop": true,
|
6
|
-
"declaration": true,
|
7
|
-
"noUnusedLocals": true,
|
8
|
-
"stripInternal": true,
|
9
|
-
"skipLibCheck": true,
|
10
|
-
"forceConsistentCasingInFileNames": true,
|
11
|
-
"allowJs": true,
|
12
|
-
"strict": true,
|
13
|
-
"types": [
|
14
|
-
"node",
|
15
|
-
],
|
16
|
-
"lib": [
|
17
|
-
"es2016"
|
18
|
-
],
|
19
|
-
"outDir": "./cli"
|
20
|
-
},
|
21
|
-
"include": ["cli"],
|
22
|
-
"exclude": ["dist", "**/proto"],
|
23
|
-
"extends": "./types/tsconfig.ecs7.strict.json"
|
24
|
-
}
|