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(ui): fix file error + add colored support #1108
Conversation
✅ Deploy Preview for vitest-dev ready!
To edit notification comments on pull requests, go to your Netlify site settings. |
To test both tabs with
// eslint-disable-next-line no-console
// console.log(`\x1B[33m${new Date().toISOString()}\x1B[0m`)
// eslint-disable-next-line no-console
// console.log(`\x1B[31m${new Error('I\'m a red fg error').stack}\x1B[0m`)
// eslint-disable-next-line no-console
// console.log(`\x1B[37m\x1B[41m${new Error('I\'m a red bg error').stack}\x1B[0m`)
// console.error('console error 1', new Error('hey there 2'))
Before merge, we can cleanup the |
ansi-to-html
support on report and console
test/core/test/basic.test.ts
Outdated
// eslint-disable-next-line no-console | ||
// console.log(`\x1B[33m${new Date().toISOString()}\x1B[0m`) | ||
// eslint-disable-next-line no-console | ||
// console.log(`\x1B[31m${new Error('I\'m a red fg error').stack}\x1B[0m`) | ||
// eslint-disable-next-line no-console | ||
// console.log(`\x1B[37m\x1B[41m${new Error('I\'m a red bg error').stack}\x1B[0m`) | ||
// console.error('console error 1', new Error('hey there 2')) |
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.
As UI testing with Cypress is enabled on Vitest, it could be great to cover your work with it :)
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 need to refactor the console view component a few to remove the client (birpc) entry (add a new component and use it on the component) and so we can only check the component, later I'll try to add a few cypress tests on ui package
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 ask me help or to @JessicaSachs who will for sure be happy to help you!
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.
@edimitchel check the console cy test : https://imgur.com/Tq4zB9g
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.
working on report tab tests
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.
@edimitchel check the report cy test: https://imgur.com/gcPyYmH
To test the console tab ( |
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.
@edimitchel now it is ready to review |
}, | ||
tasks: [], | ||
} | ||
const container = cy.mount(<ViewReport file={file} />) |
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.
Do we need TSX here? Possible to simply use h
?
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.
it is the cypress test, I just "clone" the existing one from Jess
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.
you have it on dashboard folder (the original from Jess)
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.
@antfu I can change cy tests to render the component and passing the props instead using tsx
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.
const container = cy.mount(ViewReport, {
propsData: { file }
})
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.
Ok, let's refactor it in another PR then
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.
Do we need TSX here? Possible to simply use
h
?
The reason we use TSX in such a simple example is for consistency. I prefer native h
, but I think TSX is the most elegant answer right now to:
- passing in spies for emitted events
- making components under test reactive/into playgrounds
- styling wrapper or related content
The other pattern we explored at Cy was using SFCs.
Passing Spies
const onMyEventSpy = cy.spy().as('myEventSpy')
mount(() => <MyComponent onMyEvent={onMyEventSpy}>)
cy.get('button').click().get('@myEventSpy').should('have.been.called.with', 'some arguments')
Interactive Tests
TSX becomes really helpful for modals when you not only want to spy on the event emitted (somewhat identical to wrapper.emitted()
, but also when you want to make the component into more of a playground and do something. e.g.
const visible = ref(true)
mount(() => (
<button onClick={visible.value = !visible.value}>Toggle</button>
<MyModal visible={visible}/>
))
Styling Wrapper DOM
Lastly, when you want to control parent/container styles in order to see your component behave differently in different UIs. This works especially well with UnoCSS
mount(() => (
<div min-w-200px resize overflow-auto prefers-dark>
<MyTextComponent>Content inside here!</MyTextComponent>
</div>
))
Oof. I was in the middle of adding PR feedback. |
Like a lot of it 😓 |
Oh haha, I guess you can still do and we could improve it with another PR. Thanks! |
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 ViewReport.cy.tsx
needs more help, but I added some feedback to the other spec.
In general, the goal is to say as few HTML-ish things as possible. Avoid span, children, div, etc. Try to only use a11y-friendly selectors. Part of the struggle you have in trying to write tests for these components is that there is very little accessible about them, so your test becomes tightly coupled to the markup structure.
it('test plain entry', () => { | ||
const content = new Date().toISOString() | ||
const container = cy.mount( | ||
<ViewConsoleOutputEntry | ||
task-name="test/text" | ||
type="stderr" | ||
time={Date.now()} | ||
html={false} | ||
content={content} | ||
/>, | ||
).get(textSelector) | ||
container.should('exist') | ||
container.invoke('text').then((t) => { | ||
expect(t, 'the message has the correct message').equals(content) | ||
}) | ||
}) |
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 goal this test is to make sure that there is text that has the content
you pass in when HTML is false. You also want to make sure that the type
, task-name
, and time
are visible. Here's the shortest way to write that test:
it('test plain entry', () => { | |
const content = new Date().toISOString() | |
const container = cy.mount( | |
<ViewConsoleOutputEntry | |
task-name="test/text" | |
type="stderr" | |
time={Date.now()} | |
html={false} | |
content={content} | |
/>, | |
).get(textSelector) | |
container.should('exist') | |
container.invoke('text').then((t) => { | |
expect(t, 'the message has the correct message').equals(content) | |
}) | |
}) | |
it('test plain entry', () => { | |
const content = faker.hacker.phrase() | |
const time = Date.now() | |
const localeTime = time.toLocaleString() | |
const type = 'stderr' | |
const taskName = 'test/text' | |
cy.mount( | |
<ViewConsoleOutputEntry | |
task-name={taskName} | |
type={type} | |
time={time} | |
html={false} | |
content={content} | |
/>, | |
) | |
// always either check for visible or exists | |
// visibility checks prevent CSS bugs relating to overflow, height, width, or opacity | |
cy.contains(content).should('be.visible') | |
cy.contains(taskName).should('be.visible') | |
cy.contains(localeTime).should('be.visible') | |
cy.contains(type).should('be.visible') | |
}) | |
it('test html entry', () => { | ||
const now = new Date().toISOString() | ||
const content = new Filter().toHtml(`\x1B[33m${now}\x1B[0m`) | ||
const container = cy.mount( |
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.
Don't use the return value of container
unless you want the Vue Test Utils wrapper
result.
/>, | ||
).get(htmlSelector) | ||
container.should('exist') | ||
container.children('span').then((c) => { |
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.
Instead of using DOM tags like span
and hierarchy like children
, just ask the test for what you want -- you want to find the element with the text now
.
This can be done via
cy.contains(now)
and you can delete all references to span, etc.
the contains
check implicitly checks that now
exists in the DOM so you ca delete container.should('exist')
.
cy.contains
is very similar to Testing Library's findByText
and I may suggest installing @testing-library/cypress
to have similar bindings throughout the codebase.
<ViewConsoleOutputEntry | ||
task-name="test/html" | ||
type="stderr" | ||
time={Date.now()} | ||
html={true} | ||
content={content} | ||
/>, | ||
).get(htmlSelector) | ||
container.should('exist') | ||
container.children('span').then((c) => { | ||
expect(c, 'the message has the correct message').to.have.text(now) | ||
expect(c, 'the message has the correct text color').to.have.attr('style', 'color:#A50') | ||
}) | ||
}) |
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.
@userquin is correcting me that the check for red text is actually part of the subject-under-test, in which case all that is necessary is to make the assertion more resilient against additional CSS styles being added :-)
This test is brittle because it depends on the specific CSS output of UnoCSS on styles 😮. Try to avoid these kinds of tests. I replaced the check for color:#A50
w/ the text class check, which is also brittle.
The best solution is to use visual regression testing with something like Percy, which is free for open source.
<ViewConsoleOutputEntry | |
task-name="test/html" | |
type="stderr" | |
time={Date.now()} | |
html={true} | |
content={content} | |
/>, | |
).get(htmlSelector) | |
container.should('exist') | |
container.children('span').then((c) => { | |
expect(c, 'the message has the correct message').to.have.text(now) | |
expect(c, 'the message has the correct text color').to.have.attr('style', 'color:#A50') | |
}) | |
}) | |
<ViewConsoleOutputEntry | |
task-name="test/html" | |
type="stderr" | |
time={Date.now()} | |
html={true} | |
content={content} | |
/>, | |
) | |
cy.get(htmlSelector) | |
.should('have.css', { color: '#A50' }) | |
.and('be.visible') | |
.and('contain.text', now) | |
}) |
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 resulting html is this:
<pre data-type="html"><span style="color:#A50">2022-04-07T19:10:53.637Z</span></pre>
using your suggestion, the messages aren't totally accurate (the pre
doesn't have that style, it's the inner span
that does):
This PR fixes the problem on file test compilation error and adds
ansi-to-html
support on report and console tabs.closes #494
closes #857
closes #973