-
Notifications
You must be signed in to change notification settings - Fork 2
feat(dom): DOM - toHaveStyle #154
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
25b87a7
ec10ba5
c66b17f
6efcdef
7b0938b
ab11999
5ba57a6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
import { Assertion, AssertionError } from "@assertive-ts/core"; | ||
import {parse} from '@adobe/css-tools' | ||
|
||
export class ElementAssertion<T extends Element> extends Assertion<T> { | ||
|
||
|
@@ -146,6 +147,118 @@ export class ElementAssertion<T extends Element> extends Assertion<T> { | |
return this.actual.className.split(/\s+/).filter(Boolean); | ||
} | ||
|
||
public toHaveStyle(css: Object|string): this { | ||
if ( | ||
this.actual instanceof HTMLElement || | ||
this.actual['ownerDocument'] | ||
) { | ||
|
||
const parsedCSS = typeof css === 'object' | ||
? css | ||
: parse(`selector { ${css} }`, {silent: true}).stylesheet | ||
|
||
const window = this.actual.ownerDocument.defaultView; | ||
|
||
const computedStyle = window?.getComputedStyle; | ||
|
||
const expected = parsedCSS | ||
console.log("expected: ", expected); | ||
SbsCruz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const received = computedStyle?.(this.actual); | ||
|
||
interface StyleDeclaration { | ||
property: string; | ||
value: string; | ||
} | ||
|
||
let expectedStyle = {} | ||
let receivedStyle = {} | ||
let props: string[] = [] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's try to refactor these above so that we handle mutability. |
||
|
||
const normalizer = document.createElement("div"); | ||
document.body.appendChild(normalizer); | ||
|
||
if (typeof css === 'object') { | ||
Object.entries(css).map(([property, value]) => { | ||
props = [...props, property]; | ||
|
||
normalizer.style[property] = value; | ||
const normalizedValue = window?.getComputedStyle(normalizer).getPropertyValue(property); | ||
|
||
expectedStyle = { | ||
...expectedStyle, | ||
[property]: normalizedValue?.trim(), | ||
|
||
}; | ||
Comment on lines
+181
to
+191
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Get this logic in a separate function in our helpers file. This help avoid dupllicated code below. |
||
|
||
}); | ||
console.log("EXPECTED STYLE: ", expectedStyle); | ||
} else { | ||
const expectedRule = expected.rules[0]; | ||
expectedRule.declarations.map((declaration: StyleDeclaration) => { | ||
const property = declaration.property; | ||
const value = declaration.value; | ||
|
||
props = [...props, property]; | ||
|
||
normalizer.style[property] = value; | ||
const normalizedValue = window.getComputedStyle(normalizer).getPropertyValue(property); | ||
|
||
expectedStyle = { | ||
...expectedStyle, | ||
[property]: normalizedValue.trim(), | ||
}; | ||
|
||
return expectedStyle; | ||
}); | ||
} | ||
Comment on lines
+203
to
+213
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove duplicated code by moving it to a function. |
||
|
||
document.body.removeChild(normalizer); | ||
|
||
|
||
console.log("expected style: ",expectedStyle); | ||
|
||
props.map((prop: string) => { | ||
receivedStyle = { | ||
...receivedStyle, | ||
[prop]: received?.getPropertyValue(prop).trim(), | ||
}; | ||
}) | ||
|
||
console.log("received style: ", receivedStyle); | ||
|
||
const isSameStyle = !!Object.keys(expectedStyle).length && | ||
Object.entries(expectedStyle).every(([expectedProp, expectedValue]) => { | ||
const isCustomProperty = expectedProp.startsWith('--') | ||
const spellingVariants = [expectedProp] | ||
expectedProp !== null; | ||
|
||
if (!isCustomProperty) spellingVariants.push(expectedProp.toLowerCase()) | ||
return spellingVariants.some( searchProp => | ||
receivedStyle[searchProp] === expectedValue | ||
) | ||
}) | ||
|
||
Comment on lines
+229
to
+240
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's extract this in a new function to keep our code readable and simple. |
||
console.log("isSameStyle: ", isSameStyle) | ||
const error = new AssertionError({ | ||
actual: this.actual, | ||
message: `Expected the element to have ${JSON.stringify(expectedStyle)} style`, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For a better messaging here, we can add the element in the string as well. Expected element to have ${JSON.stringify(expectedStyle)} style
|
||
expected: expectedStyle | ||
}) | ||
const invertedError = new AssertionError({ | ||
actual: this.actual, | ||
message: `Expected the element to NOT have ${JSON.stringify(expectedStyle)} style`, | ||
}) | ||
|
||
return this.execute({ | ||
assertWhen: isSameStyle, | ||
error, | ||
invertedError | ||
}); | ||
} | ||
return this; | ||
} | ||
|
||
|
||
/** | ||
* Helper method to assert the presence or absence of class names. | ||
* | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For tests, keep in mind we want to test the the error assertion and its message. Also the inverted error and its message. depending on the test add both assertions |
Uh oh!
There was an error while loading. Please reload this page.