1 /*jshint trailing:true, white:true, indent:2, strict:true, curly:true,
2 immed:true, eqeqeq:true, forin:true, latedef:true,
3 newcap:true, noarg:true, undef:true */
4 /*global XT:true, XM:true, XV:true, exports:true, describe:true, it:true,
5 require:true, __dirname:true, console:true */
8 // i.e.: A XM.ShipVia object can not be deleted if it has been assigned as the default customer ship via in sales settings.
10 // TODO: test defaults
15 var crud = require('./crud'),
16 smoke = require('./smoke'),
17 _ = require("underscore"),
18 path = require('path'),
19 assert = require("chai").assert,
20 zombieAuth = require("./zombie_auth");
22 var runSpec = function (specContents) {
27 var spec = specContents.spec;
29 describe(spec.recordType + " test", function () {
30 this.pending = spec.skipAll;
32 if (_.isString(spec.updatableField)) {
34 spec.updateHash[spec.updatableField] = "Test" + Math.random();
38 if (spec.skipBoilerplateTests && specContents.additionalTests) {
39 specContents.additionalTests();
41 } else if (spec.skipBoilerplateTests) {
46 // Run CRUD model tests
49 crud.runAllCrud(spec);
51 // even if we skip CRUD we have to create a model
52 it('can be loaded with a zombie session', function (done) {
53 this.timeout(40 * 1000);
54 zombieAuth.loadApp({callback: done, verbose: spec.verbose,
55 loginDataPath: spec.loginDataPath});
57 it('can be created', function () {
58 spec.model = new XM[spec.recordType.substring(3)]();
65 if (!spec.skipSmoke) {
66 smoke.runUICrud(spec);
69 if (!spec.skipModelConfig) {
71 // Verify required fields
73 if (spec.requiredAttributes) {
74 _.each(spec.requiredAttributes, function (attr) {
75 it("the " + attr + " attribute is required", function () {
76 assert.include(spec.model.requiredAttributes, attr);
84 it(spec.isLockable ? "is lockable" : "is not lockable", function () {
85 assert.equal(spec.isLockable, spec.model.lockable);
91 if (spec.instanceOf === "XM.Document") {
92 it("inherits from XM.Document", function () {
93 assert.isTrue(spec.model instanceof XM.Document);
95 } else if (spec.instanceOf === "XM.Model") {
96 it("inherits from XM.Model but not XM.Document", function () {
97 assert.isTrue(spec.model instanceof XM.Model);
98 assert.isFalse(spec.model instanceof XM.Document);
101 it("has its inheritance defined in the test spec", function () {
107 // Verify ID attribute
109 if (spec.idAttribute) {
110 it("has " + spec.idAttribute + " as its idAttribute", function () {
111 assert.equal(spec.idAttribute, spec.model.idAttribute);
114 it("has its id attribute defined in the test spec", function () {
120 // Verify Document Key
122 if (spec.documentKey) {
123 it("has " + spec.documentKey + " as its documentKey", function () {
124 assert.equal(spec.documentKey, spec.model.documentKey);
129 // Make sure we're testing the enforceUpperCase (the asserts themselves are in CRUD)
131 if (spec.enforceUpperKey) {
132 it((spec.enforceUpperKey ? "Enforces" : "Does not enforce") + " uppercasing the key", function () {
133 assert.equal(spec.model.enforceUpperKey, spec.enforceUpperKey);
135 if (!_.isBoolean(spec.enforceUpperKey)) {
136 it("has its enforceUpperKey convention defined in the test spec", function () {
145 _.each(spec.attributes, function (attr) {
146 it("contains the " + attr + " attribute", function () {
147 assert.include(spec.model.getAttributeNames(), attr);
150 if (!spec.attributes || spec.attributes.length === 0) {
151 it("has some attributes defined in the test spec", function () {
157 // Verify privileges are declared correctly by the extensions
159 _.each(spec.privileges, function (priv) {
160 if (typeof priv === 'string') {
161 _.each(spec.extensions, function (extension) {
162 it("has privilege " + priv + " declared by the " + extension + " extension", function () {
163 assert.isDefined(_.findWhere(XT.session.relevantPrivileges,
164 {privilege: priv, module: spec.relevantPrivilegeModule || extension}));
168 XXX this could get tripped up by non-core extensions
169 it("has privilege " + priv + " not declared by any other extensions", function () {
170 var matchedPriv = _.filter(XT.session.relevantPrivileges, function (sessionPriv) {
171 return sessionPriv.privilege === priv && !_.contains(spec.extensions, sessionPriv.module);
173 assert.equal(0, matchedPriv.length);
177 // Make sure the privilege is translated
179 it("has privilege " + priv + " that is translated in the strings file", function () {
180 var privLoc = "_" + XT.String.camelize(priv);
181 assert.notEqual(XT.String.loc(privLoc), privLoc);
189 _.each(spec.privileges, function (priv, key) {
191 createReadUpdateDelete: ["canCreate", "canRead", "canUpdate", "canDelete"],
192 createUpdateDelete: ["canCreate", "canUpdate", "canDelete"],
193 createUpdate: ["canCreate", "canUpdate"],
194 create: ["canCreate"],
196 update: ["canUpdate"],
197 delete: ["canDelete"]
199 pertinentMethods = methodMap[key],
200 updatePriv = spec.privileges.update ||
201 spec.privileges.createUpdate ||
202 spec.privileges.createUpdateDelete;
204 it("needs " + priv + " privilege to perform action " + key, function () {
205 var schema = XT.session.schemas.XM.get(XT.String.suffix(spec.recordType)),
206 personalPrivs = schema.privileges.personal,
207 Klass = XT.getObjectByName(spec.recordType);
210 //console.log("skipping personal");
211 // TODO: don't let personal privs mess us up. Find a way to test them.
212 } else if (_.isString(priv)) {
213 assert.isDefined(pertinentMethods); // make sure we're testing for the priv
214 XT.session.privileges.attributes[priv] = false;
215 if (key === "read" && updatePriv) {
216 // update privs are sufficient for read, so we have to toggle those too
217 XT.session.privileges.attributes[updatePriv] = false;
219 _.each(pertinentMethods, function (pertinentMethod) {
220 assert.isFalse(Klass[pertinentMethod]());
222 XT.session.privileges.attributes[priv] = true;
223 if (key === "read" && updatePriv) {
224 // update privs are sufficient for read, so we have to toggle those too
225 XT.session.privileges.attributes[updatePriv] = true;
227 _.each(pertinentMethods, function (pertinentMethod) {
228 assert.isTrue(Klass[pertinentMethod]());
231 } else if (_.isBoolean(priv)) {
232 _.each(pertinentMethods, function (pertinentMethod) {
233 assert.equal(Klass[pertinentMethod](), priv);
237 it("has privilege " + priv + " that's a string or boolean in the test spec", function () {
245 // Test that the collection exists
247 if (spec.collectionType) {
248 it("backs the " + spec.collectionType + " collection", function () {
249 var Collection = XT.getObjectByName(spec.collectionType),
250 modelPrototype = Collection.prototype.model.prototype,
251 editableModel = modelPrototype.editableModel || modelPrototype.recordType;
253 assert.isFunction(Collection);
254 assert.equal(editableModel, spec.recordType);
256 } else if (spec.collectionType === null) {
257 // TODO: loop through the existing collections and make sure that
258 // none are backed by spec.recordType
260 it("has no colletion specified in the test spec", function () {
266 // Test that the cache exists
268 if (spec.cacheName) {
269 it("is cached as " + spec.cacheName, function () {
270 var cache = XT.getObjectByName(spec.cacheName);
271 assert.isObject(cache);
272 assert.equal(cache.model.prototype.recordType, spec.recordType);
275 } else if (spec.cacheName === null) {
277 TODO: probably the best thing to do is to loop through the caches and make sure
278 that none of them are backed by spec.recordType
279 it("is not cached", function () {
284 it("has a cache (or null for no cache) specified in the test spec", function () {
290 // TODO: verify that the cache is made available by certain extensions and not others
291 // TODO: verify that the list is made available by certain extensions and not others
293 if (specContents.additionalTests) {
294 specContents.additionalTests();
296 if (specContents.extensionTests) {
297 specContents.extensionTests();
303 exports.runSpec = runSpec;