-
Notifications
You must be signed in to change notification settings - Fork 67
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
feat: add support to assert styles on states (hover, active) and media queries #168
feat: add support to assert styles on states (hover, active) and media queries #168
Conversation
964470f
to
e7ffa43
Compare
hey mate thanks for throwing this PR up! I'll have a look what's your thoughts on the API? I just threw something into the issue but I didn't really think about it. |
packages/jest/src/matchers.tsx
Outdated
const containsClassNames = (classNames: string[], css: string) => | ||
classNames.reduce((accum, className) => (css.includes(`.${className}`) ? true : accum), false); | ||
|
||
// sorry but using ? was throwing TS off |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the ? after MatchFilter?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes
packages/jest/src/matchers.tsx
Outdated
let matcher = c; | ||
if (state) matcher += `:${state}`; | ||
if (media) matcher = `${media}{.*${matcher}`; | ||
if (css.match(matcher)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this means if there is no matcher defined it will just mark all styles it finds as assertable yeah?
what's your thoughts on this? i can see two sides to it
- it might give false positives so people think something is working when it isnt
- we treat matchers as narrowing and its ok that the default case asserts on every state
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for reviewing. I think a better approach would be to not do a text search and to convert this into an AST and then work with rules. This is done both in emotion-jest and styled-component jest matchers.
Also, at least in jest-styled-components
matchers are mandatory and it doesn't work without narrowing, which I like too!
Let me know your thoughts and I can give it a spin.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i like it - let's give it a spin
i prefer explicit over implicit.
maybe we can also do some dev tooling help such as if we find what they're looking for in a state they haven't chosen suggest maybe looking there (can be done in another PR!)
12b877d
to
e5282a3
Compare
@Madou this is ready for review now! |
packages/jest/src/index.tsx
Outdated
toHaveCompiledCss( | ||
property: string, | ||
value: string, | ||
matchFilter?: Partial<Record<'state' | 'media', string>> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can bring in Pseudos
to make it a bit easier and then fallback to string
?
import { Pseudos } from 'csstype';
type State = Pseudos;
it does mean though every state
will be prefix with a colon however :
- maybe thats ok. (should we handle adding one if its not there?)
should we rename state
to something that encompasses other groups pseudo selectors as well? what's your thoughts
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wow, state to 'selector' maybe? I'll try this and update
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Madou if we just use the value as Pseudos, TS will automatically suggest and add :
, but then > :first-child
this won't be a valid one.
Is there a way I can preserve the intellisense as well as adding string?
Pseudos | string
is just string
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let me check it out locally and look
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
found an issue microsoft/TypeScript#29729
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
import { Pseudos } from 'csstype';
/**
* {} is used to enabled the compiler to not reduce Target down to a string.
* This keeps both Pseduos intellisense working as well as then allowing us to define anything.
* See: https://github.com/microsoft/TypeScript/issues/29729#issuecomment-460346421
*/
type AnyTarget = string & { _?: never };
type Target = Pseudos | AnyTarget;
export interface MatchFilter {
target?: Target;
media?: string;
}
this fixes it
packages/jest/src/matchers.tsx
Outdated
@@ -1,3 +1,10 @@ | |||
import CSS from 'css'; | |||
|
|||
type MatchFilter = Partial<Record<'state' | 'media', string>>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these types are duplicated in src/index.tsx
maybe we can make a types.tsx
file?
looks great man! really impressed. left a few comments 👍 as a side I need you to sign the contribution CLA - if you can have a read of https://github.com/atlassian-labs/compiled-css-in-js/blob/master/CONTRIBUTING.md and then sign "for individuals" will be great 👍 |
packages/jest/src/matchers.tsx
Outdated
}; | ||
|
||
const allRules = getAllRules(); | ||
const klass = state ? `.${className}:${state}` : `.${className}`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will we be able to assert or more complex selectors?
css={`
> :first-child {
color: red;
}
`}
expect(element).toHaveCompiledCss('color', 'red', { state: '> :first-child' });
Does that work? If not should it? (maybe we need to rename state to selector.. or target.. or something..)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wow, let me try this as well
Rename state -> target.
7851c98
to
3363921
Compare
you've done a really great job!! ❤️ |
Yay, thanks so much @Madou :D |
no worries! thank you for doing the work 🤗 |
Fixes #138. Let me know if this approach looks okay.