diff --git a/public/data/incident/1.json b/public/data/incident/1.json index 9667577917546decd4a32aad0c4ec6cb9b295170..c38bd2a40dc5c931355c4a40ff449d92f5d871b9 100644 --- a/public/data/incident/1.json +++ b/public/data/incident/1.json @@ -7,11 +7,11 @@ "updated_at": "2020-02-21T07:10:46.097Z", "comments": [ { - "created_at": "2019-11-30T16:59:22+00:0", + "created_at": "2020-03-08T00:13:00.406Z", "note": "\n
\n

Do you know if we will be able to render embedded images in comments when we\n complete work on #205166? If not, we will create an additional\n issue.

\n
\n

I'm not sure. @ohoral @splattael thoughts?

" }, { - "created_at": "2019-11-30T16:59:22+00:0", + "created_at": "2020-11-30T00:13:00.406Z", "note": "

Thank you @ameliabauerly\n for the description updates! You more captured the conversation from the call more accurately.

\n
\n

identifying which comments come from whom (even if it's just saying \"user 1\" and\n \"user 2\") will be helpful when we introduce threaded comments.

\n
\n

During our user research did the SREs talk about a need for threaded\n comments on the Status Page? I'm curious to know what their use case was as I imagine it would inform how we\n approach it.

\n

It also seems like we could hold off on identity mapping until we get to\n threaded comments. For the first iteration, I like @sarahwaldner\n 's suggestion of simply omitting the username on the public comment.

" } ] diff --git a/public/data/incident/2.json b/public/data/incident/2.json index 487ca15e39a3bcd6823e1ac1baa972b7c013965c..821796cb28766b8f8da459cd13d2c6a00440e67c 100644 --- a/public/data/incident/2.json +++ b/public/data/incident/2.json @@ -3,24 +3,24 @@ "title": "Markdown test", "status": "closed", "description": "
__Advertisement :)__\n\n- __[pica](https://nodeca.github.io/pica/demo/)__ - high quality and fast image\n  resize in browser.\n- __[babelfish](https://github.com/nodeca/babelfish/)__ - developer friendly\n  i18n with plurals support and easy syntax.\n\nYou will like those projects!
\n

h1 Heading 8-)

\n

h2 Heading

\n

h3 Heading

\n

h4 Heading

\n
h5 Heading
\n
h6 Heading
\n

Horizontal Rules

\n
\n
\n
\n

Typographic replacements

\n

Enable typographer option to see result.

\n

(c) (C) (r) (R) (tm) (TM) (p) (P) +-

\n

test.. test... test..... test?..... test!....

\n

!!!!!! ???? ,, -- ---

\n

\"Smartypants, double quotes\" and 'single quotes'

\n

Emphasis

\n

This is bold text

\n

This is bold text

\n

This is italic text

\n

This is italic text

\n

Strikethrough

\n

Blockquotes

\n
\n

Blockquotes can also be nested...

\n
\n

...by using additional greater-than signs right next to each other...

\n
\n

...or with spaces between arrows.

\n
\n
\n
\n

Lists

\n

Unordered

\n\n

Ordered

\n
    \n
  1. \n

    Lorem ipsum dolor sit amet

    \n
  2. \n
  3. \n

    Consectetur adipiscing elit

    \n
  4. \n
  5. \n

    Integer molestie lorem at massa

    \n
  6. \n
  7. \n

    You can use sequential numbers...

    \n
  8. \n
  9. \n

    ...or keep all the numbers as 1.

    \n
  10. \n
\n

Start numbering with offset:

\n
    \n
  1. foo
  2. \n
  3. bar
  4. \n
\n

Code

\n

Inline code

\n

Indented code

\n
// Some comments\nline 1 of code\nline 2 of code\nline 3 of code
\n

Block code \"fences\"

\n
Sample text here...
\n

Syntax highlighting

\n
var foo = function (bar) {\n  return bar++;\n};\n\nconsole.log(foo(5));
\n

Tables

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
OptionDescription
datapath to data files to supply the data that will be passed into templates.
engineengine to be used for processing templates. Handlebars is the default.
extextension to be used for dest files.
\n

Right aligned columns

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
OptionDescription
datapath to data files to supply the data that will be passed into templates.
engineengine to be used for processing templates. Handlebars is the default.
extextension to be used for dest files.
\n

Links

\n

link text

\n

link with title

\n

Autoconverted link https://github.com/nodeca/pica (enable linkify to see)

\n

Images

\n

\"Minion\"\n\"Stormtroopocat\"

\n

Like links, Images also have a footnote style syntax

\n

\"Alt

\n

With a reference later in the document defining the URL location:

\n

Plugins

\n

The killer feature of markdown-it is very effective support of\nsyntax plugins.

\n

Emojies

\n
\n

Classic markup: \uD83D\uDE09 :crush: \uD83D\uDE22 :tear: \uD83D\uDE06 \uD83D\uDE0B

\n

Shortcuts (emoticons): :-) :-( 8-) ;)

\n
\n

see how to change output with twemoji.

\n

\nSubscript / Superscript\n

\n\n

<ins>

\n

++Inserted text++

\n

<mark>

\n

==Marked text==

\n

Footnotes

\n

Footnote 1 link1.

\n

Footnote 2 link2.

\n

Inline footnote^[Text of inline footnote] definition.

\n

Duplicated footnote reference2.

\n

Definition lists

\n

Term 1

\n

: Definition 1\nwith lazy continuation.

\n

Term 2 with inline markup

\n

: Definition 2

\n
    { some code, part of Definition 2 }\n\nThird paragraph of definition 2.
\n

Compact style:

\n

Term 1\n~ Definition 1

\n

Term 2\n~ Definition 2a\n~ Definition 2b

\n

Abbreviations

\n

This is HTML abbreviation example.

\n

It converts \"HTML\", but keep intact partial entries like \"xxxHTMLyyy\" and so on.

\n

*[HTML]: Hyper Text Markup Language

\n

Custom containers

\n

::: warning\nhere be dragons\n:::

\n \n
    \n
  1. \n

    Footnote can have markup

    \n

    and multiple paragraphs.

    \n
  2. \n
  3. \n

    Footnote text.

    \n
  4. \n
", - "created_at": "2019-11-30T16:59:22+00:0", + "created_at": "2020-03-08T00:13:00.406Z", "updated_at": "2020-02-21T07:10:46.097Z", "comments": [ { - "created_at": "2019-11-30T16:59:22+00:0", + "created_at": "2020-03-08T00:13:00.406Z", "note": "Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit..." }, { - "created_at": "2019-11-30T16:59:22+00:0", + "created_at": "2019-11-30T00:13:00.406Z", "note": "Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit..." }, { - "created_at": "2019-11-30T16:59:22+00:0", + "created_at": "2019-11-30T00:13:00.406Z", "note": "Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit..." }, { - "created_at": "2019-11-30T16:59:22+00:0", + "created_at": "2019-01-30T00:13:00.406Z", "note": "Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit..." } ] -} +} \ No newline at end of file diff --git a/public/data/incident/3.json b/public/data/incident/3.json index a087f099974da302c65aa56270a7dd806fc6f991..14fa475285a988ae7a79b6711dd26220cefb809d 100644 --- a/public/data/incident/3.json +++ b/public/data/incident/3.json @@ -7,19 +7,19 @@ "updated_at": "2020-02-21T07:10:46.097Z", "comments": [ { - "created_at": "2019-11-30T16:59:22+00:0", + "created_at": "2020-03-08T00:13:00.406Z", "note": "Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit..." }, { - "created_at": "2019-11-30T16:59:22+00:0", + "created_at": "2020-11-30T00:13:00.406Z", "note": "Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit..." }, { - "created_at": "2019-11-30T16:59:22+00:0", + "created_at": "2020-05-30T00:13:00.406Z", "note": "Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit..." }, { - "created_at": "2019-11-30T16:59:22+00:0", + "created_at": "2020-01-30T00:13:00.406Z", "note": "Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit..." } ] diff --git a/src/components/comment.vue b/src/components/comment.vue index bf76692b0fea2526f9a1617d7d9d5b13aaafbfde..d983f6dbf8a35f9d66426f38f26c29ec5f18b7b3 100644 --- a/src/components/comment.vue +++ b/src/components/comment.vue @@ -1,11 +1,15 @@ @@ -56,11 +33,11 @@ export default { class="gl-rounded-base gl-border-r-1 gl-p-5 gl-border-1 gl-border-solid gl-border-gray-300 gl-shadow-x0-y2-b4-s0" >
- {{ createdAtDate }} + {{ formatDate(incident.created_at) }} -
-
{{ createdAtDateTime }}
-
{{ createdAtTimeZone }}
+
+
{{ formatDateTime(incident.created_at) }}
+
{{ formatDateTimeZone(incident.created_at) }}
@@ -69,8 +46,9 @@ export default { class="gl-display-inline-block gl-mt-3 text-capitalize" pill :variant="statusBadgeVariant" - >{{ incident.status }} + {{ incident.status }} +
-
{{ updatedAt }}
+
+ {{ updatedAt }} +
+ +
+
{{ formatDateTime(incident.updated_at) }}
+
{{ formatDateTimeZone(incident.updated_at) }}
+
+

Updates

diff --git a/tests/unit/components/__snapshots__/comment_spec.js.snap b/tests/unit/components/__snapshots__/comment_spec.js.snap index ae1cecbd662a65eff0c46765ad71566d1008654b..5d2074e515f05ab62cafa6c87aedeb5c6fd4dced 100644 --- a/tests/unit/components/__snapshots__/comment_spec.js.snap +++ b/tests/unit/components/__snapshots__/comment_spec.js.snap @@ -9,9 +9,29 @@ exports[`Comment renders the component 1`] = ` />
+ Posted 3 months ago +
+ + +
+
+ Feb 21, 2020 9:20am +
+ +
+ GMT+2 +
+
+
`; diff --git a/tests/unit/components/__snapshots__/list_incident_spec.js.snap b/tests/unit/components/__snapshots__/list_incident_spec.js.snap index 619085eb9b994a360c21d56e964872dc8d014de3..be42adac609b8013b6bd95996f02f68c14e5219c 100644 --- a/tests/unit/components/__snapshots__/list_incident_spec.js.snap +++ b/tests/unit/components/__snapshots__/list_incident_spec.js.snap @@ -8,23 +8,23 @@ exports[`List Incident renders the component 1`] = ` class="gl-display-inline-flex gl-align-items-center" > - February 21, 2020 + Feb 21, 2020
- Feb 21, 2020, 7:05 AM + Feb 21, 2020 9:20am
- GMT+0000 + GMT+2
@@ -41,7 +41,9 @@ exports[`List Incident renders the component 1`] = ` pill="" variant="success" > + closed + { let wrapper; const comment = { - created_at: '10/06/2020', + created_at: '2020-02-21T07:05:38.261Z', note: 'Incident update comment', }; @@ -34,10 +42,19 @@ describe('Comment', () => { }); const findText = () => wrapper.find(GlMarkdown); + const findTooltip = () => wrapper.find(GlTooltip); it('renders the component', () => { expect(wrapper.element).toMatchSnapshot(); + }); + + it('renders comment text', () => { expect(findText().exists()).toBe(true); - expect(wrapper.element.textContent).toContain(`Posted ${formattedDate}`); + }); + + it('renders comment post date with tooltip', () => { + expect(wrapper.element.textContent).toContain(`Posted ${formattedTimeAgo}`); + expect(findTooltip().exists()).toBe(true); + expect(findTooltip().text()).toContain(`${formattedDateTime} ${formattedTimezone}`); }); }); diff --git a/tests/unit/components/list_incident_spec.js b/tests/unit/components/list_incident_spec.js index 22c83ca7569e5683200b5a6a2f2f0d7953168544..5e3b2dd0d57961dbaa192f4a806f41a16bdcb7ce 100644 --- a/tests/unit/components/list_incident_spec.js +++ b/tests/unit/components/list_incident_spec.js @@ -1,5 +1,18 @@ import { shallowMount, RouterLinkStub } from '@vue/test-utils'; +import GlTooltip from '@gitlab/ui/dist/components/base/tooltip/tooltip'; +import GlBadge from '@gitlab/ui/dist/components/base/badge/badge'; import { GlListIncident } from '../../../src/components'; +import { dateTimeMixin } from '../../../src/utils/datetime'; + +jest.mock('../../../src/utils/datetime'); + +const formattedDate = 'Feb 21, 2020'; +const formattedDateTime = 'Feb 21, 2020 9:20am'; +const formattedTimezone = 'GMT+2'; + +dateTimeMixin.methods.formatDate.mockReturnValue(formattedDate); +dateTimeMixin.methods.formatDateTime.mockReturnValue(formattedDateTime); +dateTimeMixin.methods.formatDateTimeZone.mockReturnValue(formattedTimezone); describe('List Incident', () => { let wrapper; @@ -31,10 +44,23 @@ describe('List Incident', () => { } }); + const findBadge = () => wrapper.find(GlBadge); const findDate = () => wrapper.find({ ref: 'createdAtDateTime' }); + const findTooltip = () => wrapper.find(GlTooltip); it('renders the component', () => { expect(wrapper.element).toMatchSnapshot(); + }); + + it('renders status badge', () => { + expect(findBadge().exists()).toBe(true); + expect(findBadge().classes()).toContain('text-capitalize'); + }); + + it('renders posted at date with tooltip', () => { expect(findDate().exists()).toBe(true); + expect(findDate().text()).toContain(formattedDate); + expect(findTooltip().exists()).toBe(true); + expect(findTooltip().text()).toContain(`${formattedDateTime} ${formattedTimezone}`); }); }); diff --git a/tests/unit/views/__snapshots__/details_spec.js.snap b/tests/unit/views/__snapshots__/details_spec.js.snap index 8b16b4b5f698d950a438c8536c70a56dd37002d7..231fce6eb952b926a8b7b6809a22d6676d219785 100644 --- a/tests/unit/views/__snapshots__/details_spec.js.snap +++ b/tests/unit/views/__snapshots__/details_spec.js.snap @@ -54,10 +54,30 @@ exports[`Details page renders the components when data received 1`] = ` />
+ Edited 3 months ago +
+ + +
+
+ Feb 21, 2020 9:20am +
+ +
+ GMT+2 +
+
+
diff --git a/tests/unit/views/__snapshots__/list_spec.js.snap b/tests/unit/views/__snapshots__/list_spec.js.snap index 4700c5dbe8d73ad95386baab19ed4bcb0e99a533..54d26b39ea7ea9cee8c97d15d523b3f01a493bc7 100644 --- a/tests/unit/views/__snapshots__/list_spec.js.snap +++ b/tests/unit/views/__snapshots__/list_spec.js.snap @@ -13,67 +13,12 @@ exports[`List page renders the incident list when data received 1`] = `
- + +
`; diff --git a/tests/unit/views/details_spec.js b/tests/unit/views/details_spec.js index 91c86b44bbdf404f76c6bb31fd7add5a453d64d3..594351afeb2deef8812c5d0a2ecdd7accea40e57 100644 --- a/tests/unit/views/details_spec.js +++ b/tests/unit/views/details_spec.js @@ -4,11 +4,19 @@ import * as timeago from 'timeago.js'; import GlLoadingIcon from '@gitlab/ui/dist/components/base/loading_icon/loading_icon'; import GlAlert from '@gitlab/ui/dist/components/base/alert/alert'; import GlBadge from '@gitlab/ui/dist/components/base/badge/badge'; +import GlTooltip from '@gitlab/ui/dist/components/base/tooltip/tooltip'; import Details from '../../../src/views/details.vue'; import { GlMarkdown, GlComment } from '../../../src/components'; +import { dateTimeMixin } from '../../../src/utils/datetime'; jest.mock('axios'); jest.mock('timeago.js'); +jest.mock('../../../src/utils/datetime'); + +const formattedDateTime = 'Feb 21, 2020 9:20am'; +const formattedTimezone = 'GMT+2'; +dateTimeMixin.methods.formatDateTime.mockReturnValue(formattedDateTime); +dateTimeMixin.methods.formatDateTimeZone.mockReturnValue(formattedTimezone); axios.get.mockResolvedValue({ data: { @@ -16,7 +24,7 @@ axios.get.mockResolvedValue({ title: 'Title', description: 'incident', status: 'closed', - updated_at: '18.03.2020', + updated_at: '2020-02-21T07:05:38.261Z', comments: [], }, }); @@ -55,6 +63,7 @@ describe('Details page', () => { const findAlert = () => wrapper.find(GlAlert); const findBadge = () => wrapper.find(GlBadge); const findComments = () => wrapper.findAll(GlComment); + const findTooltip = () => wrapper.find(GlTooltip); it('renders the components when data received', () => { wrapper.setData({ loading: false }); @@ -63,6 +72,8 @@ describe('Details page', () => { expect(findDescription().exists()).toBe(true); expect(findLinkBack().exists()).toBe(true); expect(wrapper.element.textContent).toContain(`Edited ${formattedDate}`); + expect(findTooltip().exists()).toBe(true); + expect(findTooltip().text()).toContain(`${formattedDateTime} ${formattedTimezone}`); }); }); diff --git a/tests/unit/views/list_spec.js b/tests/unit/views/list_spec.js index 178046f56101243515829dbffd2df76b08538fd9..58dc1300da39dea8441bfacdf5022a9e88869243 100644 --- a/tests/unit/views/list_spec.js +++ b/tests/unit/views/list_spec.js @@ -18,6 +18,14 @@ axios.get.mockResolvedValue({ created_at: '2020-02-21T07:05:38.261Z', links: { details: 'data/incident/1.json' }, }, + { + id: 2, + title: 'Title', + description: 'incident2', + status: 'opened', + created_at: '2020-02-21T07:05:38.261Z', + links: { details: 'data/incident/1.json' }, + }, ], }, }); @@ -27,7 +35,7 @@ describe('List page', () => { function mountComponent() { wrapper = shallowMount(List, { - stubs: { GlLoadingIcon, GlAlert, GlListIncident, GlBadge, RouterLink: RouterLinkStub }, + stubs: { GlLoadingIcon, GlAlert, GlBadge, RouterLink: RouterLinkStub }, }); } @@ -41,21 +49,14 @@ describe('List page', () => { } }); - const findLoader = () => wrapper.find(GlLoadingIcon); const findAlert = () => wrapper.find(GlAlert); - const findIncident = () => wrapper.find(GlListIncident); - const findBadge = () => findIncident().find(GlBadge); + const findLoader = () => wrapper.find(GlLoadingIcon); + const findIncidents = () => wrapper.findAll(GlListIncident); it('renders the incident list when data received', () => { expect(wrapper.element).toMatchSnapshot(); expect(findLoader().exists()).toBe(false); - expect(findIncident().exists()).toBe(true); - }); - - it('renders the correct badge visually when data received', () => { - expect(findLoader().exists()).toBe(false); - expect(findBadge().exists()).toBe(true); - expect(findBadge().classes()).toContain('text-capitalize'); + expect(findIncidents().length).toBe(2); }); it('renders an alert when an error is received', () => {