@xrmforge/testing 0.1.0
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/dist/index.d.ts +204 -0
- package/dist/index.js +403 -0
- package/dist/index.js.map +1 -0
- package/package.json +60 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @xrmforge/testing - MockAttribute
|
|
3
|
+
*
|
|
4
|
+
* Mock implementation of Xrm.Attributes.Attribute.
|
|
5
|
+
* Tracks value changes, required level, submit mode, and onChange handlers.
|
|
6
|
+
*/
|
|
7
|
+
type OnChangeHandler = (context: Xrm.Events.EventContext) => void;
|
|
8
|
+
declare class MockAttribute {
|
|
9
|
+
private _name;
|
|
10
|
+
private _value;
|
|
11
|
+
private _initialValue;
|
|
12
|
+
private _requiredLevel;
|
|
13
|
+
private _submitMode;
|
|
14
|
+
private _onChangeHandlers;
|
|
15
|
+
constructor(name: string, value?: unknown);
|
|
16
|
+
getName(): string;
|
|
17
|
+
getValue(): unknown;
|
|
18
|
+
setValue(value: unknown): void;
|
|
19
|
+
getIsDirty(): boolean;
|
|
20
|
+
getRequiredLevel(): Xrm.Attributes.RequirementLevel;
|
|
21
|
+
setRequiredLevel(level: Xrm.Attributes.RequirementLevel): void;
|
|
22
|
+
getSubmitMode(): Xrm.SubmitMode;
|
|
23
|
+
setSubmitMode(mode: Xrm.SubmitMode): void;
|
|
24
|
+
addOnChange(handler: OnChangeHandler): void;
|
|
25
|
+
removeOnChange(handler: OnChangeHandler): void;
|
|
26
|
+
/** @internal Get registered onChange handlers (for testing/event simulation) */
|
|
27
|
+
getOnChangeHandlers(): readonly OnChangeHandler[];
|
|
28
|
+
getAttributeType(): string;
|
|
29
|
+
getFormat(): string | null;
|
|
30
|
+
getParent(): Xrm.Entity;
|
|
31
|
+
getUserPrivilege(): Xrm.Privilege;
|
|
32
|
+
controls: Xrm.Collection.ItemCollection<Xrm.Controls.Control>;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @xrmforge/testing - MockControl
|
|
37
|
+
*
|
|
38
|
+
* Mock implementation of Xrm.Controls.StandardControl.
|
|
39
|
+
* Tracks visibility, disabled state, label, and notifications.
|
|
40
|
+
*/
|
|
41
|
+
declare class MockControl {
|
|
42
|
+
private _name;
|
|
43
|
+
private _visible;
|
|
44
|
+
private _disabled;
|
|
45
|
+
private _label;
|
|
46
|
+
private _notifications;
|
|
47
|
+
constructor(name: string);
|
|
48
|
+
getName(): string;
|
|
49
|
+
getVisible(): boolean;
|
|
50
|
+
setVisible(visible: boolean): void;
|
|
51
|
+
getDisabled(): boolean;
|
|
52
|
+
setDisabled(disabled: boolean): void;
|
|
53
|
+
getLabel(): string;
|
|
54
|
+
setLabel(label: string): void;
|
|
55
|
+
setNotification(message: string, uniqueId?: string): boolean;
|
|
56
|
+
clearNotification(uniqueId?: string): boolean;
|
|
57
|
+
/** @internal Get all notifications (for assertions) */
|
|
58
|
+
getNotifications(): ReadonlyMap<string, string>;
|
|
59
|
+
getControlType(): string;
|
|
60
|
+
getParent(): Xrm.Controls.Section;
|
|
61
|
+
/** Lookup-specific: addPreSearch (no-op for non-lookup controls) */
|
|
62
|
+
addPreSearch(_handler: () => void): void;
|
|
63
|
+
/** Lookup-specific: addCustomFilter (no-op for non-lookup controls) */
|
|
64
|
+
addCustomFilter(_filter: string, _entityLogicalName?: string): void;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* @xrmforge/testing - MockUi
|
|
69
|
+
*
|
|
70
|
+
* Mock implementation of Xrm.Ui.
|
|
71
|
+
* Tracks form notifications for assertions.
|
|
72
|
+
*/
|
|
73
|
+
interface FormNotification {
|
|
74
|
+
message: string;
|
|
75
|
+
level: string;
|
|
76
|
+
}
|
|
77
|
+
declare class MockUi {
|
|
78
|
+
private _notifications;
|
|
79
|
+
setFormNotification(message: string, level: string, uniqueId: string): boolean;
|
|
80
|
+
clearFormNotification(uniqueId: string): boolean;
|
|
81
|
+
/** Get a specific notification by ID (for assertions) */
|
|
82
|
+
getFormNotification(uniqueId: string): FormNotification | undefined;
|
|
83
|
+
/** Get all notifications (for assertions) */
|
|
84
|
+
getFormNotifications(): ReadonlyMap<string, FormNotification>;
|
|
85
|
+
/** Stub: tabs.get returns a minimal Tab mock */
|
|
86
|
+
tabs: {
|
|
87
|
+
get: (name: string) => Xrm.Controls.Tab;
|
|
88
|
+
forEach: () => void;
|
|
89
|
+
getLength: () => number;
|
|
90
|
+
};
|
|
91
|
+
close(): void;
|
|
92
|
+
getFormType(): XrmEnum.FormType;
|
|
93
|
+
getViewPortHeight(): number;
|
|
94
|
+
getViewPortWidth(): number;
|
|
95
|
+
refreshRibbon(_refreshAll?: boolean): void;
|
|
96
|
+
setFormEntityName(_name: string): void;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* @xrmforge/testing - Core Types
|
|
101
|
+
*
|
|
102
|
+
* Type definitions for the form mock builder.
|
|
103
|
+
*/
|
|
104
|
+
|
|
105
|
+
/** Options for createFormMock */
|
|
106
|
+
interface CreateFormMockOptions {
|
|
107
|
+
/** Entity record ID (default: null GUID) */
|
|
108
|
+
entityId?: string;
|
|
109
|
+
/** Entity logical name (default: 'unknown') */
|
|
110
|
+
entityName?: string;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Return type of createFormMock. Provides both the typed formContext
|
|
114
|
+
* and test-friendly accessors for assertions.
|
|
115
|
+
*/
|
|
116
|
+
interface FormMock<TForm> {
|
|
117
|
+
/** Mock FormContext, typed as the generated form interface */
|
|
118
|
+
formContext: TForm;
|
|
119
|
+
/** Shorthand: getAttribute(name).getValue() */
|
|
120
|
+
getValue(name: string): unknown;
|
|
121
|
+
/** Shorthand: getAttribute(name).setValue(value) */
|
|
122
|
+
setValue(name: string, value: unknown): void;
|
|
123
|
+
/** Direct access to MockAttribute for detailed assertions */
|
|
124
|
+
getAttribute(name: string): MockAttribute;
|
|
125
|
+
/** Direct access to MockControl for detailed assertions */
|
|
126
|
+
getControl(name: string): MockControl;
|
|
127
|
+
/** Access to MockUi for notification assertions */
|
|
128
|
+
ui: MockUi;
|
|
129
|
+
/** Create an Xrm.Events.EventContext (for onLoad handlers) */
|
|
130
|
+
asEventContext(): Xrm.Events.EventContext;
|
|
131
|
+
/** Create an Xrm.Events.EventContext with getEventSource (for onChange handlers) */
|
|
132
|
+
asAttributeEventContext(fieldName: string): Xrm.Events.EventContext;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* @xrmforge/testing - createFormMock
|
|
137
|
+
*
|
|
138
|
+
* Creates a type-safe mock FormContext from a simple values object.
|
|
139
|
+
* The generated form interfaces provide compile-time field validation.
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* ```typescript
|
|
143
|
+
* import { createFormMock } from '@xrmforge/testing';
|
|
144
|
+
*
|
|
145
|
+
* const mock = createFormMock<AccountMainForm>({
|
|
146
|
+
* name: 'Contoso',
|
|
147
|
+
* revenue: 150000,
|
|
148
|
+
* });
|
|
149
|
+
*
|
|
150
|
+
* myOnLoad(mock.asEventContext());
|
|
151
|
+
* expect(mock.getValue('name')).toBe('Contoso');
|
|
152
|
+
* ```
|
|
153
|
+
*/
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Create a type-safe mock FormContext for testing D365 form scripts.
|
|
157
|
+
*
|
|
158
|
+
* @typeParam TForm - Generated form interface (e.g. AccountMainForm)
|
|
159
|
+
* @param values - Field values as a plain object (field name to value)
|
|
160
|
+
* @param options - Optional entity ID and name
|
|
161
|
+
* @returns FormMock with typed formContext and test accessors
|
|
162
|
+
*/
|
|
163
|
+
declare function createFormMock<TForm>(values?: Record<string, unknown>, options?: CreateFormMockOptions): FormMock<TForm>;
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* @xrmforge/testing - MockEntity
|
|
167
|
+
*
|
|
168
|
+
* Mock implementation of Xrm.Entity.
|
|
169
|
+
*/
|
|
170
|
+
|
|
171
|
+
declare class MockEntity {
|
|
172
|
+
private _id;
|
|
173
|
+
private _entityName;
|
|
174
|
+
private _attributes;
|
|
175
|
+
constructor(entityName: string, entityId: string, attributes: Map<string, MockAttribute>);
|
|
176
|
+
getId(): string;
|
|
177
|
+
getEntityName(): string;
|
|
178
|
+
getEntityReference(): Xrm.LookupValue;
|
|
179
|
+
getIsDirty(): boolean;
|
|
180
|
+
getPrimaryAttributeValue(): string;
|
|
181
|
+
getDataXml(): string;
|
|
182
|
+
attributes: Xrm.Collection.ItemCollection<Xrm.Attributes.Attribute>;
|
|
183
|
+
save(): Xrm.Async.PromiseLike<void>;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* @xrmforge/testing - MockEventContext
|
|
188
|
+
*
|
|
189
|
+
* Mock implementation of Xrm.Events.EventContext.
|
|
190
|
+
* Used for onLoad/onSave/onChange handler invocation.
|
|
191
|
+
*/
|
|
192
|
+
declare class MockEventContext {
|
|
193
|
+
private _formContext;
|
|
194
|
+
private _eventSource;
|
|
195
|
+
constructor(formContext: Xrm.FormContext, eventSource?: unknown);
|
|
196
|
+
getFormContext(): Xrm.FormContext;
|
|
197
|
+
getEventSource(): unknown;
|
|
198
|
+
getContext(): Xrm.GlobalContext;
|
|
199
|
+
getDepth(): number;
|
|
200
|
+
getSharedVariable(_key: string): unknown;
|
|
201
|
+
setSharedVariable(_key: string, _value: unknown): void;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export { type CreateFormMockOptions, type FormMock, type FormNotification, MockAttribute, MockControl, MockEntity, MockEventContext, MockUi, createFormMock };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
// src/mock-attribute.ts
|
|
2
|
+
var MockAttribute = class {
|
|
3
|
+
_name;
|
|
4
|
+
_value;
|
|
5
|
+
_initialValue;
|
|
6
|
+
_requiredLevel = "none";
|
|
7
|
+
_submitMode = "dirty";
|
|
8
|
+
_onChangeHandlers = [];
|
|
9
|
+
constructor(name, value = null) {
|
|
10
|
+
this._name = name;
|
|
11
|
+
this._value = value;
|
|
12
|
+
this._initialValue = value;
|
|
13
|
+
}
|
|
14
|
+
getName() {
|
|
15
|
+
return this._name;
|
|
16
|
+
}
|
|
17
|
+
getValue() {
|
|
18
|
+
return this._value;
|
|
19
|
+
}
|
|
20
|
+
setValue(value) {
|
|
21
|
+
this._value = value;
|
|
22
|
+
}
|
|
23
|
+
getIsDirty() {
|
|
24
|
+
return this._value !== this._initialValue;
|
|
25
|
+
}
|
|
26
|
+
getRequiredLevel() {
|
|
27
|
+
return this._requiredLevel;
|
|
28
|
+
}
|
|
29
|
+
setRequiredLevel(level) {
|
|
30
|
+
this._requiredLevel = level;
|
|
31
|
+
}
|
|
32
|
+
getSubmitMode() {
|
|
33
|
+
return this._submitMode;
|
|
34
|
+
}
|
|
35
|
+
setSubmitMode(mode) {
|
|
36
|
+
this._submitMode = mode;
|
|
37
|
+
}
|
|
38
|
+
addOnChange(handler) {
|
|
39
|
+
this._onChangeHandlers.push(handler);
|
|
40
|
+
}
|
|
41
|
+
removeOnChange(handler) {
|
|
42
|
+
const index = this._onChangeHandlers.indexOf(handler);
|
|
43
|
+
if (index >= 0) {
|
|
44
|
+
this._onChangeHandlers.splice(index, 1);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/** @internal Get registered onChange handlers (for testing/event simulation) */
|
|
48
|
+
getOnChangeHandlers() {
|
|
49
|
+
return this._onChangeHandlers;
|
|
50
|
+
}
|
|
51
|
+
getAttributeType() {
|
|
52
|
+
return "string";
|
|
53
|
+
}
|
|
54
|
+
getFormat() {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
getParent() {
|
|
58
|
+
return {};
|
|
59
|
+
}
|
|
60
|
+
getUserPrivilege() {
|
|
61
|
+
return { canRead: true, canUpdate: true, canCreate: true };
|
|
62
|
+
}
|
|
63
|
+
controls = {
|
|
64
|
+
forEach: () => {
|
|
65
|
+
},
|
|
66
|
+
get: (() => null),
|
|
67
|
+
getLength: () => 0
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// src/mock-control.ts
|
|
72
|
+
var MockControl = class {
|
|
73
|
+
_name;
|
|
74
|
+
_visible = true;
|
|
75
|
+
_disabled = false;
|
|
76
|
+
_label = "";
|
|
77
|
+
_notifications = /* @__PURE__ */ new Map();
|
|
78
|
+
constructor(name) {
|
|
79
|
+
this._name = name;
|
|
80
|
+
}
|
|
81
|
+
getName() {
|
|
82
|
+
return this._name;
|
|
83
|
+
}
|
|
84
|
+
getVisible() {
|
|
85
|
+
return this._visible;
|
|
86
|
+
}
|
|
87
|
+
setVisible(visible) {
|
|
88
|
+
this._visible = visible;
|
|
89
|
+
}
|
|
90
|
+
getDisabled() {
|
|
91
|
+
return this._disabled;
|
|
92
|
+
}
|
|
93
|
+
setDisabled(disabled) {
|
|
94
|
+
this._disabled = disabled;
|
|
95
|
+
}
|
|
96
|
+
getLabel() {
|
|
97
|
+
return this._label;
|
|
98
|
+
}
|
|
99
|
+
setLabel(label) {
|
|
100
|
+
this._label = label;
|
|
101
|
+
}
|
|
102
|
+
setNotification(message, uniqueId) {
|
|
103
|
+
this._notifications.set(uniqueId ?? "_default", message);
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
clearNotification(uniqueId) {
|
|
107
|
+
this._notifications.delete(uniqueId ?? "_default");
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
/** @internal Get all notifications (for assertions) */
|
|
111
|
+
getNotifications() {
|
|
112
|
+
return this._notifications;
|
|
113
|
+
}
|
|
114
|
+
getControlType() {
|
|
115
|
+
return "standard";
|
|
116
|
+
}
|
|
117
|
+
getParent() {
|
|
118
|
+
return {};
|
|
119
|
+
}
|
|
120
|
+
/** Lookup-specific: addPreSearch (no-op for non-lookup controls) */
|
|
121
|
+
addPreSearch(_handler) {
|
|
122
|
+
}
|
|
123
|
+
/** Lookup-specific: addCustomFilter (no-op for non-lookup controls) */
|
|
124
|
+
addCustomFilter(_filter, _entityLogicalName) {
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
// src/mock-entity.ts
|
|
129
|
+
var NULL_GUID = "00000000-0000-0000-0000-000000000000";
|
|
130
|
+
var MockEntity = class {
|
|
131
|
+
_id;
|
|
132
|
+
_entityName;
|
|
133
|
+
_attributes;
|
|
134
|
+
constructor(entityName, entityId, attributes) {
|
|
135
|
+
this._entityName = entityName;
|
|
136
|
+
this._id = entityId || NULL_GUID;
|
|
137
|
+
this._attributes = attributes;
|
|
138
|
+
}
|
|
139
|
+
getId() {
|
|
140
|
+
return `{${this._id}}`;
|
|
141
|
+
}
|
|
142
|
+
getEntityName() {
|
|
143
|
+
return this._entityName;
|
|
144
|
+
}
|
|
145
|
+
getEntityReference() {
|
|
146
|
+
return {
|
|
147
|
+
id: this._id,
|
|
148
|
+
entityType: this._entityName,
|
|
149
|
+
name: ""
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
getIsDirty() {
|
|
153
|
+
for (const attr of this._attributes.values()) {
|
|
154
|
+
if (attr.getIsDirty()) return true;
|
|
155
|
+
}
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
getPrimaryAttributeValue() {
|
|
159
|
+
return "";
|
|
160
|
+
}
|
|
161
|
+
getDataXml() {
|
|
162
|
+
return "";
|
|
163
|
+
}
|
|
164
|
+
attributes = {
|
|
165
|
+
forEach: () => {
|
|
166
|
+
},
|
|
167
|
+
get: (() => null),
|
|
168
|
+
getLength: () => 0
|
|
169
|
+
};
|
|
170
|
+
save() {
|
|
171
|
+
return { then: (cb) => cb() };
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
// src/mock-ui.ts
|
|
176
|
+
var MockUi = class {
|
|
177
|
+
_notifications = /* @__PURE__ */ new Map();
|
|
178
|
+
setFormNotification(message, level, uniqueId) {
|
|
179
|
+
this._notifications.set(uniqueId, { message, level });
|
|
180
|
+
return true;
|
|
181
|
+
}
|
|
182
|
+
clearFormNotification(uniqueId) {
|
|
183
|
+
this._notifications.delete(uniqueId);
|
|
184
|
+
return true;
|
|
185
|
+
}
|
|
186
|
+
/** Get a specific notification by ID (for assertions) */
|
|
187
|
+
getFormNotification(uniqueId) {
|
|
188
|
+
return this._notifications.get(uniqueId);
|
|
189
|
+
}
|
|
190
|
+
/** Get all notifications (for assertions) */
|
|
191
|
+
getFormNotifications() {
|
|
192
|
+
return this._notifications;
|
|
193
|
+
}
|
|
194
|
+
/** Stub: tabs.get returns a minimal Tab mock */
|
|
195
|
+
tabs = {
|
|
196
|
+
get: (name) => ({
|
|
197
|
+
getName: () => name,
|
|
198
|
+
getVisible: () => true,
|
|
199
|
+
setVisible: () => {
|
|
200
|
+
},
|
|
201
|
+
getDisplayState: () => "expanded",
|
|
202
|
+
setDisplayState: () => {
|
|
203
|
+
},
|
|
204
|
+
getLabel: () => name,
|
|
205
|
+
setLabel: () => {
|
|
206
|
+
},
|
|
207
|
+
setFocus: () => {
|
|
208
|
+
},
|
|
209
|
+
addTabStateChange: () => {
|
|
210
|
+
},
|
|
211
|
+
removeTabStateChange: () => {
|
|
212
|
+
},
|
|
213
|
+
getParent: () => ({}),
|
|
214
|
+
sections: {
|
|
215
|
+
forEach: () => {
|
|
216
|
+
},
|
|
217
|
+
get: ((sectionName) => ({
|
|
218
|
+
getName: () => sectionName,
|
|
219
|
+
getVisible: () => true,
|
|
220
|
+
setVisible: () => {
|
|
221
|
+
},
|
|
222
|
+
getLabel: () => sectionName,
|
|
223
|
+
setLabel: () => {
|
|
224
|
+
},
|
|
225
|
+
getParent: () => ({}),
|
|
226
|
+
controls: { forEach: () => {
|
|
227
|
+
}, get: (() => null), getLength: () => 0 }
|
|
228
|
+
})),
|
|
229
|
+
getLength: () => 0
|
|
230
|
+
},
|
|
231
|
+
controls: { forEach: () => {
|
|
232
|
+
}, get: (() => null), getLength: () => 0 }
|
|
233
|
+
}),
|
|
234
|
+
forEach: () => {
|
|
235
|
+
},
|
|
236
|
+
getLength: () => 0
|
|
237
|
+
};
|
|
238
|
+
close() {
|
|
239
|
+
}
|
|
240
|
+
getFormType() {
|
|
241
|
+
return 2;
|
|
242
|
+
}
|
|
243
|
+
getViewPortHeight() {
|
|
244
|
+
return 800;
|
|
245
|
+
}
|
|
246
|
+
getViewPortWidth() {
|
|
247
|
+
return 1200;
|
|
248
|
+
}
|
|
249
|
+
refreshRibbon(_refreshAll) {
|
|
250
|
+
}
|
|
251
|
+
setFormEntityName(_name) {
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
// src/mock-event-context.ts
|
|
256
|
+
var MockEventContext = class {
|
|
257
|
+
_formContext;
|
|
258
|
+
_eventSource;
|
|
259
|
+
constructor(formContext, eventSource) {
|
|
260
|
+
this._formContext = formContext;
|
|
261
|
+
this._eventSource = eventSource ?? formContext;
|
|
262
|
+
}
|
|
263
|
+
getFormContext() {
|
|
264
|
+
return this._formContext;
|
|
265
|
+
}
|
|
266
|
+
getEventSource() {
|
|
267
|
+
return this._eventSource;
|
|
268
|
+
}
|
|
269
|
+
getContext() {
|
|
270
|
+
return {
|
|
271
|
+
getClientUrl: () => "https://org.crm4.dynamics.com",
|
|
272
|
+
getCurrentAppUrl: () => "https://org.crm4.dynamics.com",
|
|
273
|
+
client: {
|
|
274
|
+
getClient: () => "Web",
|
|
275
|
+
getClientState: () => "Online",
|
|
276
|
+
isOffline: () => false
|
|
277
|
+
},
|
|
278
|
+
userSettings: {
|
|
279
|
+
userId: "{00000000-0000-0000-0000-000000000000}",
|
|
280
|
+
userName: "Test User",
|
|
281
|
+
languageId: 1033,
|
|
282
|
+
securityRoles: [],
|
|
283
|
+
roles: { forEach: () => {
|
|
284
|
+
}, get: (() => null), getLength: () => 0 },
|
|
285
|
+
getTimeZoneOffsetMinutes: () => 0
|
|
286
|
+
},
|
|
287
|
+
getVersion: () => "9.2.0.0",
|
|
288
|
+
isOnPremises: () => false,
|
|
289
|
+
getOrgUniqueName: () => "org",
|
|
290
|
+
getOrgLcid: () => 1033,
|
|
291
|
+
getUserLcid: () => 1033
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
getDepth() {
|
|
295
|
+
return 1;
|
|
296
|
+
}
|
|
297
|
+
getSharedVariable(_key) {
|
|
298
|
+
return void 0;
|
|
299
|
+
}
|
|
300
|
+
setSharedVariable(_key, _value) {
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
// src/create-form-mock.ts
|
|
305
|
+
function createFormMock(values = {}, options = {}) {
|
|
306
|
+
const entityName = options.entityName ?? "unknown";
|
|
307
|
+
const entityId = options.entityId ?? "00000000-0000-0000-0000-000000000000";
|
|
308
|
+
const attributes = /* @__PURE__ */ new Map();
|
|
309
|
+
const controls = /* @__PURE__ */ new Map();
|
|
310
|
+
for (const [name, value] of Object.entries(values)) {
|
|
311
|
+
attributes.set(name, new MockAttribute(name, value));
|
|
312
|
+
controls.set(name, new MockControl(name));
|
|
313
|
+
}
|
|
314
|
+
const getOrCreateAttribute = (name) => {
|
|
315
|
+
let attr = attributes.get(name);
|
|
316
|
+
if (!attr) {
|
|
317
|
+
attr = new MockAttribute(name, null);
|
|
318
|
+
attributes.set(name, attr);
|
|
319
|
+
}
|
|
320
|
+
return attr;
|
|
321
|
+
};
|
|
322
|
+
const getOrCreateControl = (name) => {
|
|
323
|
+
let ctrl = controls.get(name);
|
|
324
|
+
if (!ctrl) {
|
|
325
|
+
ctrl = new MockControl(name);
|
|
326
|
+
controls.set(name, ctrl);
|
|
327
|
+
}
|
|
328
|
+
return ctrl;
|
|
329
|
+
};
|
|
330
|
+
const mockEntity = new MockEntity(entityName, entityId, attributes);
|
|
331
|
+
const mockUi = new MockUi();
|
|
332
|
+
const formContext = {
|
|
333
|
+
getAttribute: ((nameOrIndex) => {
|
|
334
|
+
if (typeof nameOrIndex === "string") {
|
|
335
|
+
return getOrCreateAttribute(nameOrIndex);
|
|
336
|
+
}
|
|
337
|
+
if (typeof nameOrIndex === "number") {
|
|
338
|
+
return [...attributes.values()][nameOrIndex] ?? null;
|
|
339
|
+
}
|
|
340
|
+
return [...attributes.values()];
|
|
341
|
+
}),
|
|
342
|
+
getControl: ((nameOrIndex) => {
|
|
343
|
+
if (typeof nameOrIndex === "string") {
|
|
344
|
+
return getOrCreateControl(nameOrIndex);
|
|
345
|
+
}
|
|
346
|
+
if (typeof nameOrIndex === "number") {
|
|
347
|
+
return [...controls.values()][nameOrIndex] ?? null;
|
|
348
|
+
}
|
|
349
|
+
return [...controls.values()];
|
|
350
|
+
}),
|
|
351
|
+
data: {
|
|
352
|
+
entity: mockEntity,
|
|
353
|
+
process: {},
|
|
354
|
+
refresh: () => ({ then: (cb) => cb() }),
|
|
355
|
+
save: () => ({ then: (cb) => cb() }),
|
|
356
|
+
getIsDirty: () => mockEntity.getIsDirty(),
|
|
357
|
+
isValid: () => true,
|
|
358
|
+
attributes: {
|
|
359
|
+
forEach: () => {
|
|
360
|
+
},
|
|
361
|
+
get: (() => null),
|
|
362
|
+
getLength: () => attributes.size
|
|
363
|
+
}
|
|
364
|
+
},
|
|
365
|
+
ui: mockUi
|
|
366
|
+
};
|
|
367
|
+
return {
|
|
368
|
+
formContext,
|
|
369
|
+
getValue(name) {
|
|
370
|
+
return getOrCreateAttribute(name).getValue();
|
|
371
|
+
},
|
|
372
|
+
setValue(name, value) {
|
|
373
|
+
getOrCreateAttribute(name).setValue(value);
|
|
374
|
+
},
|
|
375
|
+
getAttribute(name) {
|
|
376
|
+
return getOrCreateAttribute(name);
|
|
377
|
+
},
|
|
378
|
+
getControl(name) {
|
|
379
|
+
return getOrCreateControl(name);
|
|
380
|
+
},
|
|
381
|
+
ui: mockUi,
|
|
382
|
+
asEventContext() {
|
|
383
|
+
return new MockEventContext(
|
|
384
|
+
formContext
|
|
385
|
+
);
|
|
386
|
+
},
|
|
387
|
+
asAttributeEventContext(fieldName) {
|
|
388
|
+
return new MockEventContext(
|
|
389
|
+
formContext,
|
|
390
|
+
getOrCreateAttribute(fieldName)
|
|
391
|
+
);
|
|
392
|
+
}
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
export {
|
|
396
|
+
MockAttribute,
|
|
397
|
+
MockControl,
|
|
398
|
+
MockEntity,
|
|
399
|
+
MockEventContext,
|
|
400
|
+
MockUi,
|
|
401
|
+
createFormMock
|
|
402
|
+
};
|
|
403
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/mock-attribute.ts","../src/mock-control.ts","../src/mock-entity.ts","../src/mock-ui.ts","../src/mock-event-context.ts","../src/create-form-mock.ts"],"sourcesContent":["/**\n * @xrmforge/testing - MockAttribute\n *\n * Mock implementation of Xrm.Attributes.Attribute.\n * Tracks value changes, required level, submit mode, and onChange handlers.\n */\n\ntype OnChangeHandler = (context: Xrm.Events.EventContext) => void;\n\nexport class MockAttribute {\n private _name: string;\n private _value: unknown;\n private _initialValue: unknown;\n private _requiredLevel: Xrm.Attributes.RequirementLevel = 'none';\n private _submitMode: Xrm.SubmitMode = 'dirty';\n private _onChangeHandlers: OnChangeHandler[] = [];\n\n constructor(name: string, value: unknown = null) {\n this._name = name;\n this._value = value;\n this._initialValue = value;\n }\n\n getName(): string {\n return this._name;\n }\n\n getValue(): unknown {\n return this._value;\n }\n\n setValue(value: unknown): void {\n this._value = value;\n }\n\n getIsDirty(): boolean {\n return this._value !== this._initialValue;\n }\n\n getRequiredLevel(): Xrm.Attributes.RequirementLevel {\n return this._requiredLevel;\n }\n\n setRequiredLevel(level: Xrm.Attributes.RequirementLevel): void {\n this._requiredLevel = level;\n }\n\n getSubmitMode(): Xrm.SubmitMode {\n return this._submitMode;\n }\n\n setSubmitMode(mode: Xrm.SubmitMode): void {\n this._submitMode = mode;\n }\n\n addOnChange(handler: OnChangeHandler): void {\n this._onChangeHandlers.push(handler);\n }\n\n removeOnChange(handler: OnChangeHandler): void {\n const index = this._onChangeHandlers.indexOf(handler);\n if (index >= 0) {\n this._onChangeHandlers.splice(index, 1);\n }\n }\n\n /** @internal Get registered onChange handlers (for testing/event simulation) */\n getOnChangeHandlers(): readonly OnChangeHandler[] {\n return this._onChangeHandlers;\n }\n\n getAttributeType(): string {\n return 'string';\n }\n\n getFormat(): string | null {\n return null;\n }\n\n getParent(): Xrm.Entity {\n return {} as Xrm.Entity;\n }\n\n getUserPrivilege(): Xrm.Privilege {\n return { canRead: true, canUpdate: true, canCreate: true };\n }\n\n controls: Xrm.Collection.ItemCollection<Xrm.Controls.Control> = {\n forEach: () => {},\n get: (() => null) as unknown as Xrm.Collection.ItemCollection<Xrm.Controls.Control>['get'],\n getLength: () => 0,\n };\n}\n","/**\n * @xrmforge/testing - MockControl\n *\n * Mock implementation of Xrm.Controls.StandardControl.\n * Tracks visibility, disabled state, label, and notifications.\n */\n\nexport class MockControl {\n private _name: string;\n private _visible: boolean = true;\n private _disabled: boolean = false;\n private _label: string = '';\n private _notifications: Map<string, string> = new Map();\n\n constructor(name: string) {\n this._name = name;\n }\n\n getName(): string {\n return this._name;\n }\n\n getVisible(): boolean {\n return this._visible;\n }\n\n setVisible(visible: boolean): void {\n this._visible = visible;\n }\n\n getDisabled(): boolean {\n return this._disabled;\n }\n\n setDisabled(disabled: boolean): void {\n this._disabled = disabled;\n }\n\n getLabel(): string {\n return this._label;\n }\n\n setLabel(label: string): void {\n this._label = label;\n }\n\n setNotification(message: string, uniqueId?: string): boolean {\n this._notifications.set(uniqueId ?? '_default', message);\n return true;\n }\n\n clearNotification(uniqueId?: string): boolean {\n this._notifications.delete(uniqueId ?? '_default');\n return true;\n }\n\n /** @internal Get all notifications (for assertions) */\n getNotifications(): ReadonlyMap<string, string> {\n return this._notifications;\n }\n\n getControlType(): string {\n return 'standard';\n }\n\n getParent(): Xrm.Controls.Section {\n return {} as Xrm.Controls.Section;\n }\n\n /** Lookup-specific: addPreSearch (no-op for non-lookup controls) */\n addPreSearch(_handler: () => void): void {\n // no-op\n }\n\n /** Lookup-specific: addCustomFilter (no-op for non-lookup controls) */\n addCustomFilter(_filter: string, _entityLogicalName?: string): void {\n // no-op\n }\n}\n","/**\n * @xrmforge/testing - MockEntity\n *\n * Mock implementation of Xrm.Entity.\n */\n\nimport type { MockAttribute } from './mock-attribute.js';\n\nconst NULL_GUID = '00000000-0000-0000-0000-000000000000';\n\nexport class MockEntity {\n private _id: string;\n private _entityName: string;\n private _attributes: Map<string, MockAttribute>;\n\n constructor(\n entityName: string,\n entityId: string,\n attributes: Map<string, MockAttribute>,\n ) {\n this._entityName = entityName;\n this._id = entityId || NULL_GUID;\n this._attributes = attributes;\n }\n\n getId(): string {\n return `{${this._id}}`;\n }\n\n getEntityName(): string {\n return this._entityName;\n }\n\n getEntityReference(): Xrm.LookupValue {\n return {\n id: this._id,\n entityType: this._entityName,\n name: '',\n };\n }\n\n getIsDirty(): boolean {\n for (const attr of this._attributes.values()) {\n if (attr.getIsDirty()) return true;\n }\n return false;\n }\n\n getPrimaryAttributeValue(): string {\n return '';\n }\n\n getDataXml(): string {\n return '';\n }\n\n attributes: Xrm.Collection.ItemCollection<Xrm.Attributes.Attribute> = {\n forEach: () => {},\n get: (() => null) as unknown as Xrm.Collection.ItemCollection<Xrm.Attributes.Attribute>['get'],\n getLength: () => 0,\n };\n\n save(): Xrm.Async.PromiseLike<void> {\n return { then: (cb: () => void) => cb() } as Xrm.Async.PromiseLike<void>;\n }\n}\n","/**\n * @xrmforge/testing - MockUi\n *\n * Mock implementation of Xrm.Ui.\n * Tracks form notifications for assertions.\n */\n\nexport interface FormNotification {\n message: string;\n level: string;\n}\n\nexport class MockUi {\n private _notifications: Map<string, FormNotification> = new Map();\n\n setFormNotification(message: string, level: string, uniqueId: string): boolean {\n this._notifications.set(uniqueId, { message, level });\n return true;\n }\n\n clearFormNotification(uniqueId: string): boolean {\n this._notifications.delete(uniqueId);\n return true;\n }\n\n /** Get a specific notification by ID (for assertions) */\n getFormNotification(uniqueId: string): FormNotification | undefined {\n return this._notifications.get(uniqueId);\n }\n\n /** Get all notifications (for assertions) */\n getFormNotifications(): ReadonlyMap<string, FormNotification> {\n return this._notifications;\n }\n\n /** Stub: tabs.get returns a minimal Tab mock */\n tabs = {\n get: (name: string): Xrm.Controls.Tab =>\n ({\n getName: () => name,\n getVisible: () => true,\n setVisible: () => {},\n getDisplayState: () => 'expanded' as Xrm.DisplayState,\n setDisplayState: () => {},\n getLabel: () => name,\n setLabel: () => {},\n setFocus: () => {},\n addTabStateChange: () => {},\n removeTabStateChange: () => {},\n getParent: () => ({}) as Xrm.Ui,\n sections: {\n forEach: () => {},\n get: ((sectionName: string) => ({\n getName: () => sectionName,\n getVisible: () => true,\n setVisible: () => {},\n getLabel: () => sectionName,\n setLabel: () => {},\n getParent: () => ({}) as Xrm.Controls.Tab,\n controls: { forEach: () => {}, get: (() => null) as any, getLength: () => 0 },\n })) as any,\n getLength: () => 0,\n },\n controls: { forEach: () => {}, get: (() => null) as any, getLength: () => 0 },\n }) as unknown as Xrm.Controls.Tab,\n forEach: () => {},\n getLength: () => 0,\n };\n\n close(): void {\n // no-op\n }\n\n getFormType(): XrmEnum.FormType {\n return 2 as XrmEnum.FormType; // Update\n }\n\n getViewPortHeight(): number {\n return 800;\n }\n\n getViewPortWidth(): number {\n return 1200;\n }\n\n refreshRibbon(_refreshAll?: boolean): void {\n // no-op\n }\n\n setFormEntityName(_name: string): void {\n // no-op\n }\n}\n","/**\n * @xrmforge/testing - MockEventContext\n *\n * Mock implementation of Xrm.Events.EventContext.\n * Used for onLoad/onSave/onChange handler invocation.\n */\n\nexport class MockEventContext {\n private _formContext: Xrm.FormContext;\n private _eventSource: unknown;\n\n constructor(formContext: Xrm.FormContext, eventSource?: unknown) {\n this._formContext = formContext;\n this._eventSource = eventSource ?? formContext;\n }\n\n getFormContext(): Xrm.FormContext {\n return this._formContext;\n }\n\n getEventSource(): unknown {\n return this._eventSource;\n }\n\n getContext(): Xrm.GlobalContext {\n // Minimal stub; tests that need specific GlobalContext values\n // should mock them explicitly via Object.assign or similar.\n return {\n getClientUrl: () => 'https://org.crm4.dynamics.com',\n getCurrentAppUrl: () => 'https://org.crm4.dynamics.com',\n client: {\n getClient: () => 'Web',\n getClientState: () => 'Online',\n isOffline: () => false,\n },\n userSettings: {\n userId: '{00000000-0000-0000-0000-000000000000}',\n userName: 'Test User',\n languageId: 1033,\n securityRoles: [],\n roles: { forEach: () => {}, get: (() => null) as never, getLength: () => 0 },\n getTimeZoneOffsetMinutes: () => 0,\n },\n getVersion: () => '9.2.0.0',\n isOnPremises: () => false,\n getOrgUniqueName: () => 'org',\n getOrgLcid: () => 1033,\n getUserLcid: () => 1033,\n } as unknown as Xrm.GlobalContext;\n }\n\n getDepth(): number {\n return 1;\n }\n\n getSharedVariable(_key: string): unknown {\n return undefined;\n }\n\n setSharedVariable(_key: string, _value: unknown): void {\n // no-op\n }\n}\n","/**\n * @xrmforge/testing - createFormMock\n *\n * Creates a type-safe mock FormContext from a simple values object.\n * The generated form interfaces provide compile-time field validation.\n *\n * @example\n * ```typescript\n * import { createFormMock } from '@xrmforge/testing';\n *\n * const mock = createFormMock<AccountMainForm>({\n * name: 'Contoso',\n * revenue: 150000,\n * });\n *\n * myOnLoad(mock.asEventContext());\n * expect(mock.getValue('name')).toBe('Contoso');\n * ```\n */\n\nimport type { CreateFormMockOptions, FormMock } from './types.js';\nimport { MockAttribute } from './mock-attribute.js';\nimport { MockControl } from './mock-control.js';\nimport { MockEntity } from './mock-entity.js';\nimport { MockUi } from './mock-ui.js';\nimport { MockEventContext } from './mock-event-context.js';\n\n/**\n * Create a type-safe mock FormContext for testing D365 form scripts.\n *\n * @typeParam TForm - Generated form interface (e.g. AccountMainForm)\n * @param values - Field values as a plain object (field name to value)\n * @param options - Optional entity ID and name\n * @returns FormMock with typed formContext and test accessors\n */\nexport function createFormMock<TForm>(\n values: Record<string, unknown> = {},\n options: CreateFormMockOptions = {},\n): FormMock<TForm> {\n const entityName = options.entityName ?? 'unknown';\n const entityId = options.entityId ?? '00000000-0000-0000-0000-000000000000';\n\n // Build attribute and control maps from values\n const attributes = new Map<string, MockAttribute>();\n const controls = new Map<string, MockControl>();\n\n for (const [name, value] of Object.entries(values)) {\n attributes.set(name, new MockAttribute(name, value));\n controls.set(name, new MockControl(name));\n }\n\n // Lazy-init: fields accessed but not in initial values get null\n const getOrCreateAttribute = (name: string): MockAttribute => {\n let attr = attributes.get(name);\n if (!attr) {\n attr = new MockAttribute(name, null);\n attributes.set(name, attr);\n }\n return attr;\n };\n\n const getOrCreateControl = (name: string): MockControl => {\n let ctrl = controls.get(name);\n if (!ctrl) {\n ctrl = new MockControl(name);\n controls.set(name, ctrl);\n }\n return ctrl;\n };\n\n const mockEntity = new MockEntity(entityName, entityId, attributes);\n const mockUi = new MockUi();\n\n // Build the formContext object that satisfies the TForm interface\n const formContext = {\n getAttribute: ((nameOrIndex?: string | number) => {\n if (typeof nameOrIndex === 'string') {\n return getOrCreateAttribute(nameOrIndex);\n }\n if (typeof nameOrIndex === 'number') {\n return [...attributes.values()][nameOrIndex] ?? null;\n }\n return [...attributes.values()];\n }) as Xrm.FormContext['getAttribute'],\n\n getControl: ((nameOrIndex?: string | number) => {\n if (typeof nameOrIndex === 'string') {\n return getOrCreateControl(nameOrIndex);\n }\n if (typeof nameOrIndex === 'number') {\n return [...controls.values()][nameOrIndex] ?? null;\n }\n return [...controls.values()];\n }) as Xrm.FormContext['getControl'],\n\n data: {\n entity: mockEntity as unknown as Xrm.Entity,\n process: {} as Xrm.ProcessFlow.ProcessManager,\n refresh: () =>\n ({ then: (cb: () => void) => cb() }) as Xrm.Async.PromiseLike<void>,\n save: () =>\n ({ then: (cb: () => void) => cb() }) as Xrm.Async.PromiseLike<void>,\n getIsDirty: () => mockEntity.getIsDirty(),\n isValid: () => true,\n attributes: {\n forEach: () => {},\n get: (() => null) as any,\n getLength: () => attributes.size,\n },\n },\n\n ui: mockUi as unknown as Xrm.Ui,\n } as unknown as TForm;\n\n return {\n formContext,\n\n getValue(name: string): unknown {\n return getOrCreateAttribute(name).getValue();\n },\n\n setValue(name: string, value: unknown): void {\n getOrCreateAttribute(name).setValue(value);\n },\n\n getAttribute(name: string): MockAttribute {\n return getOrCreateAttribute(name);\n },\n\n getControl(name: string): MockControl {\n return getOrCreateControl(name);\n },\n\n ui: mockUi,\n\n asEventContext(): Xrm.Events.EventContext {\n return new MockEventContext(\n formContext as unknown as Xrm.FormContext,\n ) as unknown as Xrm.Events.EventContext;\n },\n\n asAttributeEventContext(fieldName: string): Xrm.Events.EventContext {\n return new MockEventContext(\n formContext as unknown as Xrm.FormContext,\n getOrCreateAttribute(fieldName),\n ) as unknown as Xrm.Events.EventContext;\n },\n };\n}\n"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@xrmforge/testing",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Type-safe testing utilities for Dynamics 365 form scripts",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"dynamics-365",
|
|
7
|
+
"typescript",
|
|
8
|
+
"xrm",
|
|
9
|
+
"testing",
|
|
10
|
+
"mock",
|
|
11
|
+
"form-scripts",
|
|
12
|
+
"dataverse"
|
|
13
|
+
],
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"author": "XrmForge Contributors",
|
|
16
|
+
"homepage": "https://github.com/juergenbeck/XrmForge/tree/main/packages/testing",
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "https://github.com/juergenbeck/XrmForge.git",
|
|
20
|
+
"directory": "packages/testing"
|
|
21
|
+
},
|
|
22
|
+
"bugs": {
|
|
23
|
+
"url": "https://github.com/juergenbeck/XrmForge/issues"
|
|
24
|
+
},
|
|
25
|
+
"type": "module",
|
|
26
|
+
"main": "./dist/index.js",
|
|
27
|
+
"types": "./dist/index.d.ts",
|
|
28
|
+
"exports": {
|
|
29
|
+
".": {
|
|
30
|
+
"types": "./dist/index.d.ts",
|
|
31
|
+
"import": "./dist/index.js",
|
|
32
|
+
"default": "./dist/index.js"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"files": [
|
|
36
|
+
"dist"
|
|
37
|
+
],
|
|
38
|
+
"sideEffects": false,
|
|
39
|
+
"scripts": {
|
|
40
|
+
"build": "tsup",
|
|
41
|
+
"dev": "tsup --watch",
|
|
42
|
+
"test": "vitest run",
|
|
43
|
+
"test:watch": "vitest",
|
|
44
|
+
"typecheck": "tsc --noEmit",
|
|
45
|
+
"lint": "eslint src/",
|
|
46
|
+
"clean": "rm -rf dist"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@types/node": "^22.0.0",
|
|
50
|
+
"tsup": "^8.3.0",
|
|
51
|
+
"typescript": "^5.7.0",
|
|
52
|
+
"vitest": "^3.0.0"
|
|
53
|
+
},
|
|
54
|
+
"peerDependencies": {
|
|
55
|
+
"@types/xrm": ">=9.0.0"
|
|
56
|
+
},
|
|
57
|
+
"engines": {
|
|
58
|
+
"node": ">=20.0.0"
|
|
59
|
+
}
|
|
60
|
+
}
|