Skip to content
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

Merged
merged 11 commits into from Apr 7, 2022

Conversation

userquin
Copy link
Member

@userquin userquin commented Apr 5, 2022

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

@netlify
Copy link

netlify bot commented Apr 5, 2022

Deploy Preview for vitest-dev ready!

Name Link
🔨 Latest commit 85f65a2
🔍 Latest deploy log https://app.netlify.com/sites/vitest-dev/deploys/624f080be9dc1f0008917b9a
😎 Deploy Preview https://deploy-preview-1108--vitest-dev.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site settings.

@userquin
Copy link
Member Author

userquin commented Apr 6, 2022

To test both tabs with ansi colors:

  • base cases: cd packages/core && pnpm run dev:ui then from root folder pnpm run test: open the page and uncomment the console entries from the ui on basic.test.ts (search basic on left panel):
  // 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'))
  • @testing-library/xxx: from root folder pnpm run ui:build then cd examples\react-testing-lib && pnpm run test:ui: change for example on examples/react-testing-lib/src/components/input.test.tsx line 19 with name: /email address/g (change the i with g on regex)

https://streamable.com/kw340u

Before merge, we can cleanup the console on test/core/test/basic.test.ts.

@userquin userquin marked this pull request as ready for review April 6, 2022 19:53
@userquin userquin marked this pull request as draft April 6, 2022 21:22
@userquin userquin changed the title feat(ui): add ansi-to-html support on report and console chore(ui): fix file error + add colored support Apr 6, 2022
@userquin userquin marked this pull request as ready for review April 6, 2022 21:35
@userquin userquin marked this pull request as draft April 6, 2022 21:57
@userquin userquin marked this pull request as ready for review April 6, 2022 22:09
@antfu antfu changed the title chore(ui): fix file error + add colored support feat(ui): fix file error + add colored support Apr 6, 2022
@edimitchel edimitchel self-requested a review April 7, 2022 07:58
packages/vitest/src/types/tasks.ts Outdated Show resolved Hide resolved
Comment on lines 6 to 12
// 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'))
Copy link
Member

@edimitchel edimitchel Apr 7, 2022

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 :)

Copy link
Member Author

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

Copy link
Member

@edimitchel edimitchel Apr 7, 2022

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!

Copy link
Member Author

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

Copy link
Member Author

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

Copy link
Member Author

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

@userquin
Copy link
Member Author

userquin commented Apr 7, 2022

To test the console tab (ViewConsoleOutputentry.vue component) with cypress run cd packages/ui && pnpm run test:open.

Copy link
Member

@edimitchel edimitchel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice @userquin, you rock!
That's ok for me, @antfu your turn :)

@userquin
Copy link
Member Author

userquin commented Apr 7, 2022

Very nice @userquin, you rock!
That's ok for me, @antfu your turn :)

@edimitchel

I need to include the cypress tests for the report tab as well, just wait I'm working on it, I'm going to eat in 1 hour or so I'll be back and finish it.

@userquin
Copy link
Member Author

userquin commented Apr 7, 2022

@edimitchel now it is ready to review

},
tasks: [],
}
const container = cy.mount(<ViewReport file={file} />)
Copy link
Member

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?

Copy link
Member Author

@userquin userquin Apr 7, 2022

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

Copy link
Member Author

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)

Copy link
Member Author

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

Copy link
Member Author

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 } 
})

Copy link
Member

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

Copy link
Contributor

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:

  1. passing in spies for emitted events
  2. making components under test reactive/into playgrounds
  3. 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>
))

@antfu antfu merged commit b737476 into main Apr 7, 2022
@antfu antfu deleted the userquin/feat-ui-add-ansi-color branch April 7, 2022 18:23
@JessicaSachs
Copy link
Contributor

Oof. I was in the middle of adding PR feedback.

@JessicaSachs
Copy link
Contributor

Like a lot of it 😓

@antfu
Copy link
Member

antfu commented Apr 7, 2022

Oh haha, I guess you can still do and we could improve it with another PR. Thanks!

Copy link
Contributor

@JessicaSachs JessicaSachs left a 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.

Comment on lines +8 to +23
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)
})
})
Copy link
Contributor

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:

Suggested change
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(
Copy link
Contributor

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) => {
Copy link
Contributor

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.

Comment on lines +28 to +41
<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')
})
})
Copy link
Contributor

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.

Suggested change
<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)
})

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JessicaSachs

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):

imagen

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
4 participants