Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 24 additions & 11 deletions vendor/wheels/tests/specs/model/ModelSurfaceCoverageSpec.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ component extends="wheels.WheelsTest" {
*/
function run() {

// The post class's callbacks before any spec here runs, for the no-leftover check below.
variables.postCallbacksAtStart = SerializeJSON(application.wo.$canonicalCacheValue(value = application.wo.model("post").$classData().callbacks));

describe("model layer surfaces", () => {

describe("ScopeChain terminal methods", () => {
Expand Down Expand Up @@ -84,17 +87,27 @@ component extends="wheels.WheelsTest" {

it("registers the remaining lifecycle callbacks and clears them", () => {
var m = model("post");
m.afterInitialization();
m.afterNew();
m.afterUpdate();
m.afterValidation();
m.afterValidationOnCreate();
m.afterValidationOnUpdate();
m.beforeUpdate();
m.beforeValidationOnCreate();
m.beforeValidationOnUpdate();
// Revert so no phantom callback fires on later specs.
m.$clearCallbacks();
// Put back exactly what the class had: $clearCallbacks() with no type would also
// drop callbacks the class was configured with.
var postClass = m.$classData();
var savedCallbacks = Duplicate(postClass.callbacks);
try {
m.afterInitialization();
m.afterNew();
m.afterUpdate();
m.afterValidation();
m.afterValidationOnCreate();
m.afterValidationOnUpdate();
m.beforeUpdate();
m.beforeValidationOnCreate();
m.beforeValidationOnUpdate();
} finally {
postClass.callbacks = savedCallbacks;
}
});

it("leaves the post class with only the callbacks it was configured with", () => {
expect(SerializeJSON(application.wo.$canonicalCacheValue(value = model("post").$classData().callbacks))).toBe(variables.postCallbacksAtStart);
});

it("$coerceOracleTimestamp delegates to the engine adapter", () => {
Expand Down
28 changes: 21 additions & 7 deletions vendor/wheels/tests/specs/model/hardener/ModelHardenerM2M8Spec.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ component extends="wheels.WheelsTest" {
function run() {

g = application.wo
// The post class's validations before any spec here runs, for the no-leftover check below.
variables.postValidationsAtStart = SerializeJSON(application.wo.$canonicalCacheValue(value = g.model("post").$classData().validations));

describe("M2 validatesUniquenessOf includeSoftDeletes default", () => {

Expand All @@ -23,16 +25,28 @@ component extends="wheels.WheelsTest" {
});

it("still treats a soft-deleted row as taken when includeSoftDeletes is true", () => {
transaction action="begin" {
var orgPost = g.model("post").findOne();
var newPost = g.model("post").new(orgPost.properties());
orgPost.delete();
newPost.validatesUniquenessOf(properties = "title", includeSoftDeletes = true);
expect(newPost.valid()).toBeFalse();
transaction action="rollback";
// validatesUniquenessOf() on an object registers on the shared post class, so put the
// class's validations back afterwards or every later post save carries this one too.
var postClass = g.model("post").$classData();
var savedValidations = Duplicate(postClass.validations);
try {
transaction action="begin" {
var orgPost = g.model("post").findOne();
var newPost = g.model("post").new(orgPost.properties());
orgPost.delete();
newPost.validatesUniquenessOf(properties = "title", includeSoftDeletes = true);
expect(newPost.valid()).toBeFalse();
transaction action="rollback";
}
} finally {
postClass.validations = savedValidations;
}
});

it("leaves the post class with only the validations it was configured with", () => {
expect(SerializeJSON(application.wo.$canonicalCacheValue(value = g.model("post").$classData().validations))).toBe(variables.postValidationsAtStart);
});

});

describe("M3 QueryBuilder single-arg where is raw SQL", () => {
Expand Down
25 changes: 20 additions & 5 deletions vendor/wheels/tests/specs/model/transactionsSpec.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ component extends="wheels.WheelsTest" {
g = application.wo
var _isCockroachDB = CreateObject("component", "wheels.migrator.Migration").init().adapter.adapterName() == "CockroachDB";

// The tagWithDataCallbacks class's callbacks before any spec here runs, for the no-leftover check.
variables.tagCallbacksAtStart = SerializeJSON(application.wo.$canonicalCacheValue(value = g.model("tagWithDataCallbacks").$classData().callbacks))

describe("Tests that invokewithtransaction", () => {

beforeEach(() => {
Expand Down Expand Up @@ -259,15 +262,27 @@ component extends="wheels.WheelsTest" {
it("rollback when error raised", () => {
if (_isCockroachDB) return;
tagModel = g.model("tagWithDataCallbacks").new(name = "Kermit", description = "The Frog")
tagModel.afterSave(methods = "crashMe")
// afterSave() on an object registers on the shared class: put its callbacks back so
// later saves of this model don't run crashMe.
var tagClass = tagModel.$classData()
var savedCallbacks = Duplicate(tagClass.callbacks)
try {
tagModel.save()
} catch (any e) {
results = g.model("tag").findAll(where = "name = 'Kermit'")
tagModel.afterSave(methods = "crashMe")
try {
tagModel.save()
} catch (any e) {
results = g.model("tag").findAll(where = "name = 'Kermit'")
}
} finally {
tagClass.callbacks = savedCallbacks
}

expect(results.recordcount).toBe(0)
})

it("leaves the tagWithDataCallbacks class with only the callbacks it was configured with", () => {
expect(SerializeJSON(application.wo.$canonicalCacheValue(value = g.model("tagWithDataCallbacks").$classData().callbacks))).toBe(variables.tagCallbacksAtStart)
})
})
}
}
14 changes: 14 additions & 0 deletions vendor/wheels/tests/specs/view/formsSpec.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ component extends="wheels.WheelsTest" {
* app's values back afterwards.
*/
function beforeAll() {
// The tag class's validations as configured, to check nothing below leaves one behind.
variables.tagValidationsAtStart = SerializeJSON(application.wo.$canonicalCacheValue(value = application.wo.model("tag").$classData().validations));
variables.pinnedFormSettings = {includeFormErrorMessages = application.wheels.includeFormErrorMessages, labelPlacement = {}};
application.wheels.includeFormErrorMessages = false;
for (var helperName in ListToArray("textField,textArea,passwordField,select,fileField,emailField,urlField,numberField,telField,dateField,searchField,colorField,rangeField")) {
Expand Down Expand Up @@ -430,12 +432,17 @@ component extends="wheels.WheelsTest" {
g.set(functionName = "textFieldTag", encode = false)
// Reset tag model for BoxLang compatibility
tagModel = g.model("tag")
// validatesPresenceOf() on a tag object registers on the shared tag class, so a later
// tag save anywhere in the run would fail it; put the class's validations back after.
savedTagValidations = Duplicate(tagModel.$classData().validations)
})

afterEach(() => {
g.set(functionName = "checkBoxTag", encode = true)
g.set(functionName = "textField", encode = true)
g.set(functionName = "textFieldTag", encode = true)
var tagClass = g.model("tag").$classData()
tagClass.validations = Duplicate(savedTagValidations)
})

it("adds label to the left", () => {
Expand Down Expand Up @@ -553,6 +560,13 @@ component extends="wheels.WheelsTest" {
})
})

describe("The tag class after the label specs", () => {

it("keeps only the validations it was configured with", () => {
expect(SerializeJSON(application.wo.$canonicalCacheValue(value = g.model("tag").$classData().validations))).toBe(variables.tagValidationsAtStart)
})
})

describe("Tests that passwordField", () => {

it("is valid", () => {
Expand Down
Loading