@a5c-ai/krate 5.0.1-staging.00fa5317c
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/Dockerfile +31 -0
- package/README.md +183 -0
- package/bin/krate-demo.mjs +23 -0
- package/bin/krate-server.mjs +14 -0
- package/dist/krate-controller-ui.json +3205 -0
- package/dist/krate-lifecycle.json +201 -0
- package/dist/krate-runtime-snapshot.json +3125 -0
- package/dist/krate-summary.json +724 -0
- package/docs/README.md +61 -0
- package/docs/agents/README.md +83 -0
- package/docs/agents/acceptance-test-matrix.md +193 -0
- package/docs/agents/agent-mux-adapter-contract.md +167 -0
- package/docs/agents/agent-mux-source-map.md +310 -0
- package/docs/agents/agent-run-memory-import-spec.md +256 -0
- package/docs/agents/agent-stack-management-spec.md +421 -0
- package/docs/agents/api-contract-spec.md +309 -0
- package/docs/agents/artifacts-writeback-spec.md +145 -0
- package/docs/agents/chart-packaging-spec.md +128 -0
- package/docs/agents/ci-orchestration-spec.md +140 -0
- package/docs/agents/context-assembly-spec.md +219 -0
- package/docs/agents/controller-reconciliation-spec.md +255 -0
- package/docs/agents/crd-schema-spec.md +315 -0
- package/docs/agents/decision-log-open-questions.md +169 -0
- package/docs/agents/developer-implementation-checklist.md +329 -0
- package/docs/agents/dispatching-design.md +262 -0
- package/docs/agents/gaps-agent-mux-to-krate-crds.md +298 -0
- package/docs/agents/glossary.md +66 -0
- package/docs/agents/implementation-blueprint.md +324 -0
- package/docs/agents/implementation-rollout-slices.md +251 -0
- package/docs/agents/memory-context-integration-spec.md +194 -0
- package/docs/agents/memory-ontology-schema-spec.md +253 -0
- package/docs/agents/memory-operations-runbook.md +121 -0
- package/docs/agents/mvp-vertical-slice-spec.md +146 -0
- package/docs/agents/observability-audit-spec.md +265 -0
- package/docs/agents/operator-runbook.md +174 -0
- package/docs/agents/org-memory-api-payload-examples.md +333 -0
- package/docs/agents/org-memory-controller-sequence-spec.md +181 -0
- package/docs/agents/org-memory-e2e-fixture-plan.md +161 -0
- package/docs/agents/org-memory-ui-implementation-map.md +114 -0
- package/docs/agents/org-memory-vertical-slice-spec.md +168 -0
- package/docs/agents/org-resource-model-delta-spec.md +111 -0
- package/docs/agents/org-route-resource-model-spec.md +183 -0
- package/docs/agents/org-scoping-namespace-spec.md +114 -0
- package/docs/agents/rbac-secrets-management-spec.md +406 -0
- package/docs/agents/repository-page-integration-spec.md +255 -0
- package/docs/agents/resource-contract-examples.md +808 -0
- package/docs/agents/resource-relationship-map.md +190 -0
- package/docs/agents/security-threat-model.md +188 -0
- package/docs/agents/shared-memory-company-brain-spec.md +358 -0
- package/docs/agents/storage-migration-spec.md +168 -0
- package/docs/agents/subagent-orchestration-spec.md +152 -0
- package/docs/agents/system-overview.md +88 -0
- package/docs/agents/tools-mcp-skills-spec.md +189 -0
- package/docs/agents/traceability-matrix.md +79 -0
- package/docs/agents/ui-flow-spec.md +211 -0
- package/docs/agents/ui-ux-system-spec.md +426 -0
- package/docs/agents/workspace-lifecycle-spec.md +166 -0
- package/docs/architecture-spec.md +78 -0
- package/docs/components/control-plane.md +78 -0
- package/docs/components/data-plane.md +69 -0
- package/docs/components/hooks-events.md +67 -0
- package/docs/components/identity-rbac-policy.md +73 -0
- package/docs/components/kubevela-oam.md +70 -0
- package/docs/components/operations-publishing.md +81 -0
- package/docs/components/runners-ci.md +66 -0
- package/docs/components/web-ui.md +94 -0
- package/docs/external/README.md +47 -0
- package/docs/external/bidirectional-sync-design.md +134 -0
- package/docs/external/cicd-interface.md +64 -0
- package/docs/external/external-backend-controllers.md +170 -0
- package/docs/external/external-backend-crds.md +234 -0
- package/docs/external/external-backend-ui-spec.md +151 -0
- package/docs/external/external-backend-ux-flows.md +115 -0
- package/docs/external/external-object-mapping.md +125 -0
- package/docs/external/git-forge-interface.md +68 -0
- package/docs/external/github-integration-design.md +151 -0
- package/docs/external/issue-tracking-interface.md +66 -0
- package/docs/external/provider-capability-manifests.md +204 -0
- package/docs/external/provider-catalog.md +139 -0
- package/docs/external/provider-rollout-testing.md +78 -0
- package/docs/external/research-results.md +48 -0
- package/docs/external/security-auth-permissions.md +81 -0
- package/docs/external/sync-state-machines.md +108 -0
- package/docs/external/unified-external-backend-model.md +107 -0
- package/docs/external/user-facing-changes.md +67 -0
- package/docs/gaps.md +161 -0
- package/docs/install.md +94 -0
- package/docs/krate-design.md +334 -0
- package/docs/local-minikube.md +55 -0
- package/docs/ontology/README.md +32 -0
- package/docs/ontology/bounded-contexts.md +29 -0
- package/docs/ontology/events-and-hooks.md +32 -0
- package/docs/ontology/oam-kubevela.md +32 -0
- package/docs/ontology/operations-and-release.md +25 -0
- package/docs/ontology/personas-and-actors.md +32 -0
- package/docs/ontology/policies-and-invariants.md +33 -0
- package/docs/ontology/problem-space.md +30 -0
- package/docs/ontology/resource-contracts.md +40 -0
- package/docs/ontology/resource-taxonomy.md +42 -0
- package/docs/ontology/runners-and-ci.md +29 -0
- package/docs/ontology/solution-space.md +24 -0
- package/docs/ontology/storage-and-data-boundaries.md +29 -0
- package/docs/ontology/validation-matrix.md +24 -0
- package/docs/ontology/web-ui-excellent-flows.md +32 -0
- package/docs/ontology/workflows.md +39 -0
- package/docs/ontology/world.md +35 -0
- package/docs/openapi.yaml +1275 -0
- package/docs/product-requirements.md +62 -0
- package/docs/roadmap-mvp.md +87 -0
- package/docs/system-requirements.md +90 -0
- package/docs/tests/README.md +53 -0
- package/docs/tests/agent-qa-plan.md +63 -0
- package/docs/tests/browser-ui-tests.md +62 -0
- package/docs/tests/ci-quality-gates.md +48 -0
- package/docs/tests/coverage-model.md +64 -0
- package/docs/tests/e2e-scenario-tests.md +53 -0
- package/docs/tests/fixtures-test-data.md +63 -0
- package/docs/tests/observability-reliability-tests.md +54 -0
- package/docs/tests/product-test-matrix.md +145 -0
- package/docs/tests/qa-adoption-roadmap.md +130 -0
- package/docs/tests/qa-automation-plan.md +101 -0
- package/docs/tests/security-compliance-tests.md +57 -0
- package/docs/tests/test-framework-tools.md +88 -0
- package/docs/tests/test-suite-layout.md +121 -0
- package/docs/tests/unit-integration-tests.md +48 -0
- package/docs/todo-kyverno +714 -0
- package/docs/todos.md +4 -0
- package/docs/user-stories.md +78 -0
- package/examples/minikube-demo.yaml +190 -0
- package/examples/oam-application.yaml +23 -0
- package/examples/policy-kyverno-pr-title.yaml +18 -0
- package/package.json +63 -0
- package/scripts/build.mjs +29 -0
- package/scripts/setup-minikube.mjs +65 -0
- package/scripts/smoke.mjs +37 -0
- package/scripts/validate-doc-coverage.mjs +152 -0
- package/scripts/validate-package.mjs +93 -0
- package/scripts/validate-ui.mjs +278 -0
- package/src/agent-adapter-controller.js +169 -0
- package/src/agent-approval-controller.js +170 -0
- package/src/agent-context-bundles.js +242 -0
- package/src/agent-dispatch-controller.js +209 -0
- package/src/agent-gateway-config-controller.js +147 -0
- package/src/agent-memory-controller.js +357 -0
- package/src/agent-memory-import.js +327 -0
- package/src/agent-memory-query.js +292 -0
- package/src/agent-memory-repository-source-controller.js +255 -0
- package/src/agent-mux-client.js +280 -0
- package/src/agent-permission-review.js +250 -0
- package/src/agent-project-controller.js +117 -0
- package/src/agent-provider-config-controller.js +150 -0
- package/src/agent-secret-config-grant-controller.js +282 -0
- package/src/agent-session-transcript-controller.js +189 -0
- package/src/agent-stack-controller.js +347 -0
- package/src/agent-subagent-controller.js +160 -0
- package/src/agent-transport-binding-controller.js +121 -0
- package/src/agent-trigger-controller.js +381 -0
- package/src/agent-workspace-controller.js +702 -0
- package/src/agent-writeback-controller.js +302 -0
- package/src/api-controller.js +541 -0
- package/src/argocd-gitops.js +43 -0
- package/src/async-controller.js +207 -0
- package/src/audit-controller.js +191 -0
- package/src/auth.js +307 -0
- package/src/component-catalog.js +41 -0
- package/src/control-plane.js +136 -0
- package/src/controller-client.js +72 -0
- package/src/controller-ui.js +617 -0
- package/src/data-plane.js +179 -0
- package/src/event-bus.js +61 -0
- package/src/external/conflict-controller.js +225 -0
- package/src/external/github/auth.js +96 -0
- package/src/external/github/cicd.js +180 -0
- package/src/external/github/git-forge.js +240 -0
- package/src/external/github/index.js +144 -0
- package/src/external/github/issue-tracking.js +163 -0
- package/src/external/provider-adapter.js +161 -0
- package/src/external/provider-resource-factory.js +161 -0
- package/src/external/sync-controller.js +235 -0
- package/src/external/webhook-controller.js +144 -0
- package/src/external/write-controller.js +283 -0
- package/src/gitea-backend.js +131 -0
- package/src/gitea-service.js +173 -0
- package/src/handoff.js +98 -0
- package/src/hooks-events.js +63 -0
- package/src/http-server.js +377 -0
- package/src/identity-policy.js +86 -0
- package/src/index.js +57 -0
- package/src/kubernetes-controller-async.js +511 -0
- package/src/kubernetes-controller.js +878 -0
- package/src/kubernetes-resource-gateway.js +48 -0
- package/src/notification-controller.js +178 -0
- package/src/operations.js +112 -0
- package/src/org-scoping.js +5 -0
- package/src/resource-model.js +221 -0
- package/src/runner-controller.js +272 -0
- package/src/runners-ci.js +48 -0
- package/src/runtime.js +196 -0
- package/src/snapshot-cache.js +157 -0
- package/src/web-ui.js +40 -0
- package/tests/agent-adapter-controller.test.js +361 -0
- package/tests/agent-approval-controller.test.js +173 -0
- package/tests/agent-context-bundles.test.js +278 -0
- package/tests/agent-dispatch-controller.test.js +315 -0
- package/tests/agent-gateway-config-controller.test.js +386 -0
- package/tests/agent-memory-controller.test.js +308 -0
- package/tests/agent-memory-import-snapshot.test.js +477 -0
- package/tests/agent-memory-query.test.js +404 -0
- package/tests/agent-memory-repository-source.test.js +514 -0
- package/tests/agent-mux-client.test.js +204 -0
- package/tests/agent-permission-review-v2.test.js +317 -0
- package/tests/agent-permission-review.test.js +209 -0
- package/tests/agent-project-controller.test.js +302 -0
- package/tests/agent-provider-config-controller.test.js +376 -0
- package/tests/agent-resources.test.js +228 -0
- package/tests/agent-secret-config-grant.test.js +231 -0
- package/tests/agent-session-transcript-controller.test.js +499 -0
- package/tests/agent-stack-controller.test.js +221 -0
- package/tests/agent-subagent-controller.test.js +201 -0
- package/tests/agent-transport-binding-controller.test.js +294 -0
- package/tests/agent-trigger-controller.test.js +211 -0
- package/tests/agent-trigger-routes.test.js +190 -0
- package/tests/agent-trigger-sources.test.js +245 -0
- package/tests/agent-workspace-controller.test.js +181 -0
- package/tests/agent-writeback.test.js +292 -0
- package/tests/approval-persistence.test.js +171 -0
- package/tests/async-controller.test.js +252 -0
- package/tests/audit-controller.test.js +227 -0
- package/tests/codespace-controller.test.js +318 -0
- package/tests/deployment.test.js +407 -0
- package/tests/e2e/lifecycle.test.js +117 -0
- package/tests/event-bus-integration.test.js +190 -0
- package/tests/external-github-forge.test.js +560 -0
- package/tests/external-github-issues-cicd.test.js +520 -0
- package/tests/external-integration.test.js +470 -0
- package/tests/external-persistence.test.js +340 -0
- package/tests/external-provider-adapter.test.js +365 -0
- package/tests/external-resource-model.test.js +215 -0
- package/tests/external-webhook-sync.test.js +287 -0
- package/tests/external-write-conflict.test.js +353 -0
- package/tests/gitea-service.test.js +253 -0
- package/tests/health-check-real.test.js +165 -0
- package/tests/integration/full-flow.test.js +266 -0
- package/tests/krate.test.js +756 -0
- package/tests/memory-search-wiring.test.js +270 -0
- package/tests/notification-controller.test.js +196 -0
- package/tests/notification-integration.test.js +179 -0
- package/tests/org-scoping.test.js +687 -0
- package/tests/runner-controller.test.js +327 -0
- package/tests/runner-integration.test.js +231 -0
- package/tests/session-cookie-hmac.test.js +151 -0
- package/tests/snapshot-performance.test.js +247 -0
- package/tests/sse-events.test.js +107 -0
- package/tests/webhook-trigger.test.js +198 -0
- package/tests/workspace-volumes.test.js +312 -0
- package/tests/writeback-persistence.test.js +207 -0
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Event bus integration tests
|
|
3
|
+
*
|
|
4
|
+
* Exercises the event bus pub/sub mechanism with multiple subscribers,
|
|
5
|
+
* emitResourceChange field validation, unsubscribe isolation, and the
|
|
6
|
+
* globalEventBus singleton.
|
|
7
|
+
*/
|
|
8
|
+
import assert from 'node:assert/strict';
|
|
9
|
+
import test from 'node:test';
|
|
10
|
+
import { createEventBus, globalEventBus } from '../src/event-bus.js';
|
|
11
|
+
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
// globalEventBus.emit notifies all subscribers
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
|
|
16
|
+
test('globalEventBus.emit notifies all subscribers', () => {
|
|
17
|
+
// Use a local bus to avoid cross-test pollution from the module singleton
|
|
18
|
+
const bus = createEventBus();
|
|
19
|
+
const receivedA = [];
|
|
20
|
+
const receivedB = [];
|
|
21
|
+
|
|
22
|
+
bus.subscribe((e) => receivedA.push(e));
|
|
23
|
+
bus.subscribe((e) => receivedB.push(e));
|
|
24
|
+
|
|
25
|
+
bus.emit({ type: 'integration-test', value: 'ping' });
|
|
26
|
+
|
|
27
|
+
assert.equal(receivedA.length, 1);
|
|
28
|
+
assert.equal(receivedB.length, 1);
|
|
29
|
+
assert.equal(receivedA[0].value, 'ping');
|
|
30
|
+
assert.equal(receivedB[0].value, 'ping');
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test('globalEventBus is a shared singleton — same object across imports', async () => {
|
|
34
|
+
// Re-import to confirm it's the same singleton reference
|
|
35
|
+
const { globalEventBus: bus2 } = await import('../src/event-bus.js');
|
|
36
|
+
assert.strictEqual(globalEventBus, bus2, 'globalEventBus must be a module-level singleton');
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
// emitResourceChange includes correct fields
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
|
|
43
|
+
test('emitResourceChange includes kind, name, operation, type, and timestamp fields', () => {
|
|
44
|
+
const bus = createEventBus();
|
|
45
|
+
const events = [];
|
|
46
|
+
bus.subscribe((e) => events.push(e));
|
|
47
|
+
|
|
48
|
+
bus.emitResourceChange('Repository', 'my-repo', 'apply');
|
|
49
|
+
|
|
50
|
+
assert.equal(events.length, 1);
|
|
51
|
+
const ev = events[0];
|
|
52
|
+
assert.equal(ev.type, 'resource-change');
|
|
53
|
+
assert.equal(ev.kind, 'Repository');
|
|
54
|
+
assert.equal(ev.name, 'my-repo');
|
|
55
|
+
assert.equal(ev.operation, 'apply');
|
|
56
|
+
assert.ok(typeof ev.timestamp === 'string', 'timestamp must be a string');
|
|
57
|
+
assert.ok(new Date(ev.timestamp).getTime() > 0, 'timestamp must be a valid ISO date');
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test('emitResourceChange for delete operation includes operation: delete', () => {
|
|
61
|
+
const bus = createEventBus();
|
|
62
|
+
const events = [];
|
|
63
|
+
bus.subscribe((e) => events.push(e));
|
|
64
|
+
|
|
65
|
+
bus.emitResourceChange('AgentStack', 'review-bot', 'delete');
|
|
66
|
+
|
|
67
|
+
const ev = events[0];
|
|
68
|
+
assert.equal(ev.operation, 'delete');
|
|
69
|
+
assert.equal(ev.kind, 'AgentStack');
|
|
70
|
+
assert.equal(ev.name, 'review-bot');
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test('emitResourceChange broadcasts to all currently subscribed listeners', () => {
|
|
74
|
+
const bus = createEventBus();
|
|
75
|
+
const counts = [0, 0, 0];
|
|
76
|
+
bus.subscribe(() => counts[0]++);
|
|
77
|
+
bus.subscribe(() => counts[1]++);
|
|
78
|
+
bus.subscribe(() => counts[2]++);
|
|
79
|
+
|
|
80
|
+
bus.emitResourceChange('Pipeline', 'ci-pipeline', 'apply');
|
|
81
|
+
|
|
82
|
+
assert.deepEqual(counts, [1, 1, 1]);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
// ---------------------------------------------------------------------------
|
|
86
|
+
// unsubscribe stops notifications
|
|
87
|
+
// ---------------------------------------------------------------------------
|
|
88
|
+
|
|
89
|
+
test('unsubscribe stops further notifications to the removed listener', () => {
|
|
90
|
+
const bus = createEventBus();
|
|
91
|
+
const events = [];
|
|
92
|
+
const listener = (e) => events.push(e);
|
|
93
|
+
|
|
94
|
+
bus.subscribe(listener);
|
|
95
|
+
bus.emit({ type: 'before-unsub' });
|
|
96
|
+
|
|
97
|
+
bus.unsubscribe(listener);
|
|
98
|
+
bus.emit({ type: 'after-unsub' });
|
|
99
|
+
|
|
100
|
+
assert.equal(events.length, 1);
|
|
101
|
+
assert.equal(events[0].type, 'before-unsub');
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test('unsubscribing one listener does not affect other listeners', () => {
|
|
105
|
+
const bus = createEventBus();
|
|
106
|
+
const eventsA = [];
|
|
107
|
+
const eventsB = [];
|
|
108
|
+
const listenerA = (e) => eventsA.push(e);
|
|
109
|
+
const listenerB = (e) => eventsB.push(e);
|
|
110
|
+
|
|
111
|
+
bus.subscribe(listenerA);
|
|
112
|
+
bus.subscribe(listenerB);
|
|
113
|
+
|
|
114
|
+
bus.emit({ type: 'first' });
|
|
115
|
+
bus.unsubscribe(listenerA);
|
|
116
|
+
bus.emit({ type: 'second' });
|
|
117
|
+
|
|
118
|
+
assert.equal(eventsA.length, 1, 'listenerA should only have received the first event');
|
|
119
|
+
assert.equal(eventsB.length, 2, 'listenerB should have received both events');
|
|
120
|
+
assert.equal(eventsB[1].type, 'second');
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
test('unsubscribing a listener that was never subscribed is a no-op', () => {
|
|
124
|
+
const bus = createEventBus();
|
|
125
|
+
const listener = () => {};
|
|
126
|
+
// Should not throw
|
|
127
|
+
assert.doesNotThrow(() => bus.unsubscribe(listener));
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
// ---------------------------------------------------------------------------
|
|
131
|
+
// Multiple subscribers receive same event
|
|
132
|
+
// ---------------------------------------------------------------------------
|
|
133
|
+
|
|
134
|
+
test('five subscribers all receive the same emitted event object', () => {
|
|
135
|
+
const bus = createEventBus();
|
|
136
|
+
const buckets = Array.from({ length: 5 }, () => []);
|
|
137
|
+
buckets.forEach((bucket) => bus.subscribe((e) => bucket.push(e)));
|
|
138
|
+
|
|
139
|
+
const event = { type: 'multi-fan-out', id: 'event-xyz' };
|
|
140
|
+
bus.emit(event);
|
|
141
|
+
|
|
142
|
+
for (const bucket of buckets) {
|
|
143
|
+
assert.equal(bucket.length, 1, 'each subscriber should receive exactly one event');
|
|
144
|
+
assert.strictEqual(bucket[0], event, 'each subscriber should receive the same event reference');
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
test('emit with zero subscribers does not throw and is a no-op', () => {
|
|
149
|
+
const bus = createEventBus();
|
|
150
|
+
assert.doesNotThrow(() => bus.emit({ type: 'nobody-home' }));
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
test('subscribers added after an emit do not receive previous events', () => {
|
|
154
|
+
const bus = createEventBus();
|
|
155
|
+
const events = [];
|
|
156
|
+
|
|
157
|
+
bus.emit({ type: 'before-subscribe' });
|
|
158
|
+
bus.subscribe((e) => events.push(e));
|
|
159
|
+
|
|
160
|
+
assert.equal(events.length, 0, 'late subscriber must not receive past events');
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// ---------------------------------------------------------------------------
|
|
164
|
+
// Sequential emit ordering
|
|
165
|
+
// ---------------------------------------------------------------------------
|
|
166
|
+
|
|
167
|
+
test('emit delivers events to subscribers in subscription order', () => {
|
|
168
|
+
const bus = createEventBus();
|
|
169
|
+
const order = [];
|
|
170
|
+
|
|
171
|
+
bus.subscribe(() => order.push('first'));
|
|
172
|
+
bus.subscribe(() => order.push('second'));
|
|
173
|
+
bus.subscribe(() => order.push('third'));
|
|
174
|
+
|
|
175
|
+
bus.emit({ type: 'ordering-test' });
|
|
176
|
+
|
|
177
|
+
assert.deepEqual(order, ['first', 'second', 'third']);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
test('multiple emits are each delivered to all subscribers independently', () => {
|
|
181
|
+
const bus = createEventBus();
|
|
182
|
+
const events = [];
|
|
183
|
+
bus.subscribe((e) => events.push(e.id));
|
|
184
|
+
|
|
185
|
+
bus.emit({ id: 1 });
|
|
186
|
+
bus.emit({ id: 2 });
|
|
187
|
+
bus.emit({ id: 3 });
|
|
188
|
+
|
|
189
|
+
assert.deepEqual(events, [1, 2, 3]);
|
|
190
|
+
});
|