4 var _ = require("underscore"),
5 assert = require("chai").assert;
7 var navigateToList = exports.navigateToList = function (app, listKind) {
8 var navigator = app.$.postbooks.$.navigator,
13 // Drill down into the appropriate module
15 _.each(navigator.modules, function (module, moduleIndex) {
16 _.each(module.panels, function (panel, panelIndex) {
17 if (listKind && panel.kind === listKind) {
18 myModuleIndex = moduleIndex;
19 myPanelIndex = panelIndex;
23 assert.isDefined(myPanelIndex, "Cannot find " + listKind + " in any module panels");
24 navigator.setModule(myModuleIndex);
25 navigator.setContentPanel(myPanelIndex);
30 Finds the list in the panels and opens up a new workspace from that list.
32 var navigateToNewWorkspace = exports.navigateToNewWorkspace = function (app, listKind, done) {
33 var navigator, workspaceContainer, model, autoRegex, eventName, idChanged;
35 navigator = navigateToList(app, listKind);
37 // Create a new record
39 navigator.newRecord({}, {originator: {}});
40 workspaceContainer = app.$.postbooks.getActive();
41 assert.isDefined(workspaceContainer);
42 assert.equal(workspaceContainer.kind, "XV.WorkspaceContainer");
43 model = workspaceContainer.$.workspace.value;
45 autoRegex = XM.Document.AUTO_NUMBER + "|" + XM.Document.AUTO_OVERRIDE_NUMBER;
46 if (model instanceof XM.Document && model.numberPolicy.match(autoRegex)) {
47 // wait for the model to fetch its id if appropriate
49 // the id is already defined? No need to wait for it from the server, then.
50 done(workspaceContainer);
53 eventName = "change:" + model.idAttribute;
54 idChanged = function () {
56 model.off(eventName, idChanged);
57 done(workspaceContainer);
60 model.on(eventName, idChanged);
62 done(workspaceContainer);
66 var navigateToExistingWorkspace = exports.navigateToExistingWorkspace = function (app, listKind, done) {
67 var workspaceContainer,
69 navigator = navigateToList(app, listKind),
70 list = navigator.$.contentPanels.getActive(),
71 collection = list.value,
74 * Open workspace backed by the given model.
77 navigate = function (model, status, options) {
79 * This lets us begin listening for events from workspace.value before
81 * @listens lock:obtain
83 XM.Tuplespace.once('lock:obtain', function (_model, lock) {
84 // console.log('\na ' + _model.recordType + ' obtained lock!');
86 workspaceContainer = app.$.postbooks.getActive();
87 assert.isDefined(workspaceContainer);
89 workspace = workspaceContainer.$.workspace;
90 assert.isDefined(workspace);
91 assert.isDefined(workspace.value);
93 if (_model.id !== workspace.value.id) {
97 done(workspaceContainer);
104 navigator.doWorkspace({
105 workspace: list.getWorkspace(),
111 * Navigate to workspace of first model in the list.
113 if (collection.getStatus() === XM.Model.READY_CLEAN) {
114 navigate(collection.at(0));
116 collection.once('status:READY_CLEAN', navigate);
121 Applies the attributes to the model by bubbling up the values
122 from the widgets in the workspace.
124 var setWorkspaceAttributes = exports.setWorkspaceAttributes = function (workspace, createHash) {
125 _.each(createHash, function (value, key) {
126 var widgetFound = false,
129 _.each(workspace.$, function (widget) {
130 if (widget.attr === key) {
132 widget.doValueChange({value: value});
135 assert.isTrue(widgetFound, "Cannot find widget for attr " + key + " in workspace " + workspace.kind);
136 attribute = workspace.value.get(key);
137 if (attribute.idAttribute && !value.idAttribute) {
138 // the attribute has been turned into a model
139 assert.equal(attribute.id, value[attribute.idAttribute]);
141 } else if (key === workspace.value.idAttribute && workspace.value.enforceUpperKey) {
142 // the model uppercases the key
143 assert.equal(workspace.value.get(key), value.toUpperCase());
146 assert.equal(workspace.value.get(key), value);
152 Save the model through the workspace and make sure it saved ok.
154 var saveWorkspace = exports.saveWorkspace = function (workspace, done, skipValidation) {
155 var invalid = function (model, err) {
156 workspace.value.off('invalid', invalid);
160 assert.isTrue(workspace.value.hasLockKey(), "Cannot acquire lock key");
162 if (!skipValidation) {
163 var validation = workspace.value.validate(workspace.value.attributes);
164 assert.isUndefined(validation, "Failed validation with error: " + JSON.stringify(validation));
167 workspace.value.on('invalid', invalid);
168 //workspace.value.on('all', function (event, model, err) {
169 // console.log("save event", event, model && model.id);
172 // wait until the list has been refreshed with this model before we return control
173 modelChangeDone: function () {
174 var lockChange = function () {
175 workspace.value.off("lockChange", lockChange);
176 done(null, workspace.value);
178 workspace.value.on("lockChange", lockChange);
179 workspace.value.releaseLock();
181 error: function (err) {
182 assert.fail(JSON.stringify(err));
187 var deleteFromList = exports.deleteFromList = function (app, model, done) {
191 app.$.postbooks.previous();
192 assert.equal(app.$.postbooks.getActive().kind, "XV.Navigator");
195 var list = app.$.postbooks.getActive().$.contentPanels.getActive(),
196 // find the new model by id
197 // TODO: what if the new model is off the page and cannot be found?
198 listModel = _.find(list.value.models, function (m) {
199 return m.get(m.idAttribute) === model.id;
202 statusChange = function (model, status) {
203 if (status === XM.Model.DESTROYED_DIRTY) {
204 model.off("statusChange", statusChange);
205 assert.equal(XT.app.$.postbooks.getActive().kind, "XV.Navigator");
206 // XXX we have to wait for the list to know the model is gone,
207 // or else the next test might pick it up in BUSY_FETCHING status
208 setTimeout(function () {
213 model.on("statusChange", statusChange);
215 // delete it, by calling the function that gets called when the user ok's the delete popup
216 list.deleteItem({model: listModel});
219 exports.updateFirstModel = function (test) {
220 it('should allow a trivial update to the first model of ' + test.kind, function (done) {
221 this.timeout(20 * 1000);
222 navigateToExistingWorkspace(XT.app, test.kind, function (workspaceContainer) {
225 workspace = workspaceContainer.$.workspace;
227 assert.equal(workspace.value.recordType, test.model);
228 if (typeof test.update === 'string') {
230 updateObj[test.update] = "Test" + Math.random();
231 } else if (typeof test.update === 'object') {
232 updateObj = test.update;
234 statusChanged = function () {
235 if (workspace.value.getStatus() === XM.Model.READY_CLEAN) {
236 workspace.value.off("statusChange", statusChanged);
237 setWorkspaceAttributes(workspace, updateObj);
238 saveWorkspace(workspace, function () {
239 XT.app.$.postbooks.previous();
240 assert.equal(XT.app.$.postbooks.getActive().kind, "XV.Navigator");
245 workspace.value.on("statusChange", statusChanged);
250 exports.runUICrud = function (spec) {
251 var workspaceContainer,
253 it('can get to a new workspace', function (done) {
254 this.timeout(10 * 1000);
255 navigateToNewWorkspace(XT.app, spec.listKind, function (_workspaceContainer) {
256 workspaceContainer = _workspaceContainer;
260 it('can set the workspace attributes', function () {
261 workspace = workspaceContainer.$.workspace;
262 assert.equal(workspace.value.recordType, spec.recordType);
263 setWorkspaceAttributes(workspace, spec.createHash);
265 _.each(spec.beforeSaveUIActions || [], function (spec) {
266 it(spec.it, function (done) {
267 this.timeout(20 * 1000);
268 spec.action(workspace, done);
271 it('can save the workspace', function (done) {
272 this.timeout(20 * 1000);
273 if (spec.captureObject) {
275 XG.capturedId = workspace.value.id;
277 saveWorkspace(workspace, done);
279 if (spec.captureObject) {
282 it('can delete the item from the list', function (done) {
283 this.timeout(20 * 1000);
284 deleteFromList(XT.app, workspace.value, done);