-
-
Notifications
You must be signed in to change notification settings - Fork 148
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(target-observer): fix dom binding update when initial value match…
…es empty string fixes #423
- Loading branch information
Showing
2 changed files
with
181 additions
and
0 deletions.
There are no files selected for viewing
180 changes: 180 additions & 0 deletions
180
packages/jit-html/test/integration/html-attributes.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
import { InjectArray } from '@aurelia/kernel'; | ||
import { Aurelia, CustomElementResource as CE, ICustomElement, INode, LifecycleFlags as LF } from '@aurelia/runtime'; | ||
import { expect } from 'chai'; | ||
import { TestContext } from '../util'; | ||
import { eachCartesianJoin } from './util'; | ||
|
||
interface IThing { | ||
enabled?: boolean; | ||
} | ||
type VM<T> = T & ICustomElement<Node> & { | ||
el: Element; | ||
parent?: VM<T>; | ||
}; | ||
interface Spec { | ||
t: string; | ||
} | ||
|
||
describe('html attribute', function() { | ||
function setup() { | ||
const ctx = TestContext.createHTMLTestContext(); | ||
|
||
const host = ctx.createElement('div'); | ||
const au = new Aurelia(ctx.container); | ||
return { ctx, host, au }; | ||
} | ||
|
||
describe('class', function () { | ||
describe('on a surrogate', function () { | ||
interface ThingSpec extends Spec { | ||
createThing(): IThing; | ||
} | ||
interface ExpressionSpec extends Spec { | ||
expression: string; | ||
getExpectedClassNames(thing: IThing): string[]; | ||
} | ||
|
||
const thingSpecs: ThingSpec[] = [ | ||
{ t: '1', createThing() { return { enabled: false }; } }, | ||
{ t: '2', createThing() { return { enabled: true }; } }, | ||
{ t: '3', createThing() { return { }; } } | ||
]; | ||
const expressionSpecs: ExpressionSpec[] = [ | ||
{ | ||
t: '1', | ||
expression: '${thing.enabled?\'class-1\':\'\'}', | ||
getExpectedClassNames(thing: IThing) { | ||
return thing && thing.enabled ? ['au', 'class-1'] : ['au']; | ||
} | ||
}, | ||
{ | ||
t: '2', | ||
expression: '${thing.enabled?\'class-1\':\'class-2\'}', | ||
getExpectedClassNames(thing: IThing) { | ||
return thing && thing.enabled ? ['au', 'class-1'] : ['au', 'class-2']; | ||
} | ||
}, | ||
{ | ||
t: '3', | ||
expression: '${thing.enabled?\'class-1\':\'\'} class-3', | ||
getExpectedClassNames(thing: IThing) { | ||
return thing && thing.enabled ? ['au', 'class-3', 'class-1'] : ['au', 'class-3']; | ||
} | ||
}, | ||
{ | ||
t: '4', | ||
expression: '${thing.enabled?\'class-1\':\'class-2\'} class-3', | ||
getExpectedClassNames(thing: IThing) { | ||
return thing && thing.enabled ? ['au', 'class-3', 'class-1'] : ['au', 'class-2', 'class-3']; | ||
} | ||
}, | ||
{ | ||
t: '5', | ||
expression: 'class-0 ${thing.enabled?\'class-1\':\'\'}', | ||
getExpectedClassNames(thing: IThing) { | ||
return thing && thing.enabled ? ['au', 'class-0', 'class-1'] : ['au', 'class-0']; | ||
} | ||
}, | ||
{ | ||
t: '6', | ||
expression: 'class-0 ${thing.enabled?\'class-1\':\'class-2\'}', | ||
getExpectedClassNames(thing: IThing) { | ||
return thing && thing.enabled ? ['au', 'class-0', 'class-1'] : ['au', 'class-0', 'class-2']; | ||
} | ||
}, | ||
{ | ||
t: '7', | ||
expression: 'class-0 ${thing.enabled?\'class-1\':\'\'} class-3', | ||
getExpectedClassNames(thing: IThing) { | ||
return thing && thing.enabled ? ['au', 'class-0', 'class-3', 'class-1'] : ['au', 'class-0', 'class-3']; | ||
} | ||
}, | ||
{ | ||
t: '8', | ||
expression: 'class-0 ${thing.enabled?\'class-1\':\'class-2\'} class-3', | ||
getExpectedClassNames(thing: IThing) { | ||
return thing && thing.enabled ? ['au', 'class-0', 'class-3', 'class-1'] : ['au', 'class-0', 'class-2', 'class-3']; | ||
} | ||
}, | ||
]; | ||
|
||
eachCartesianJoin( | ||
[thingSpecs, thingSpecs, thingSpecs, thingSpecs, expressionSpecs], | ||
function (thingSpec1, thingSpec2, thingSpec3, thingSpec4, expressionSpec) { | ||
it(`${thingSpec1.t} ${thingSpec2.t} ${thingSpec3.t} ${thingSpec4.t} ${expressionSpec.t}`, function() { | ||
const { createThing: createThing1 } = thingSpec1; | ||
const { createThing: createThing2 } = thingSpec2; | ||
const { createThing: createThing3 } = thingSpec3; | ||
const { createThing: createThing4 } = thingSpec4; | ||
const { expression, getExpectedClassNames } = expressionSpec; | ||
|
||
const thing1 = createThing1(); | ||
const thing2 = createThing2(); | ||
const thing3 = createThing3(); | ||
const thing4 = createThing4(); | ||
|
||
const { host, au } = setup(); | ||
// verify that the assertions inside change handler / lifecycles were actually performed | ||
let assertionCount = 0; | ||
|
||
const component = CE.define( | ||
{ | ||
name: 'app', | ||
template: `<foo parent.bind="$this"></foo>`, | ||
dependencies: [ | ||
CE.define( | ||
{ | ||
name: 'foo', | ||
template: `<template class="${expression}"></template>`, | ||
bindables: ['thing', 'parent'] | ||
}, | ||
class { | ||
public static readonly inject: InjectArray = [INode]; | ||
public thing: IThing; | ||
constructor(public el: Element) { | ||
this.thing = thing1; | ||
} | ||
|
||
public attached(): void { | ||
this.thing = thing2; | ||
this.thing = thing3; | ||
this.thing = thing4; | ||
} | ||
|
||
public thingChanged(this: VM<this>, newValue: IThing, oldValue: IThing): void { | ||
this.verifyClassName(oldValue); | ||
this.$lifecycle.processFlushQueue(LF.none); | ||
this.verifyClassName(newValue); | ||
} | ||
|
||
private verifyClassName(this: VM<this>, thing: IThing): void { | ||
const actualClassNames: string[] = []; | ||
this.el.classList.forEach(c => { actualClassNames.push(c); }); | ||
const expectedClassNames = getExpectedClassNames(thing); | ||
expect(actualClassNames.length, `actualClassNames.length #${++assertionCount}`).to.equal(expectedClassNames.length); | ||
for (const expectedClassName of expectedClassNames) { | ||
expect(actualClassNames, `actualClassNames #${++assertionCount}`).to.include(expectedClassName); | ||
} | ||
} | ||
} | ||
) | ||
] | ||
}, | ||
class { | ||
public static readonly inject: InjectArray = [INode]; | ||
constructor(public el: Element) {} | ||
} | ||
); | ||
|
||
au.app({ host, component }); | ||
au.start(); | ||
|
||
expect(assertionCount, 'assertionCount').to.be.gte(12); | ||
|
||
au.stop(); | ||
}); | ||
} | ||
); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters