/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import { module, test } from 'qunit';
import sinon from 'sinon';
import { setupRenderingTest } from 'ember-qunit';
import { find, render, findAll } from '@ember/test-helpers';
import { hbs } from 'ember-cli-htmlbars';
import { format, formatRFC3339, subMonths } from 'date-fns';
import timestamp from 'core/utils/timestamp';
module('Integration | Component | clients/line-chart', function (hooks) {
setupRenderingTest(hooks);
hooks.before(function () {
sinon.stub(timestamp, 'now').callsFake(() => new Date('2018-04-03T14:15:30'));
});
hooks.beforeEach(function () {
this.set('xKey', 'foo');
this.set('yKey', 'bar');
this.set('dataset', [
{
foo: '2018-04-03T14:15:30',
bar: 4,
expectedLabel: '4/18',
},
{
foo: '2018-05-03T14:15:30',
bar: 8,
expectedLabel: '5/18',
},
{
foo: '2018-06-03T14:15:30',
bar: 14,
expectedLabel: '6/18',
},
{
foo: '2018-07-03T14:15:30',
bar: 10,
expectedLabel: '7/18',
},
]);
});
hooks.after(function () {
timestamp.now.restore();
});
test('it renders', async function (assert) {
await render(hbs`
`);
assert.dom('[data-test-line-chart]').exists('Chart is rendered');
assert
.dom('[data-test-line-chart="plot-point"]')
.exists({ count: this.dataset.length }, `renders ${this.dataset.length} plot points`);
findAll('[data-test-x-axis] text').forEach((e, i) => {
// For some reason the first axis label is not rendered
assert
.dom(e)
.hasText(
`${this.dataset[i].expectedLabel}`,
`renders x-axis label: ${this.dataset[i].expectedLabel}`
);
});
assert.dom('[data-test-y-axis] text').hasText('0', `y-axis starts at 0`);
});
test('it renders upgrade data', async function (assert) {
const now = timestamp.now();
this.set('dataset', [
{
foo: formatRFC3339(subMonths(now, 4)),
bar: 4,
month: format(subMonths(now, 4), 'M/yy'),
},
{
foo: formatRFC3339(subMonths(now, 3)),
bar: 8,
month: format(subMonths(now, 3), 'M/yy'),
},
{
foo: formatRFC3339(subMonths(now, 2)),
bar: 14,
month: format(subMonths(now, 2), 'M/yy'),
},
{
foo: formatRFC3339(subMonths(now, 1)),
bar: 10,
month: format(subMonths(now, 1), 'M/yy'),
},
]);
this.set('upgradeData', [
{
id: '1.10.1',
previousVersion: '1.9.2',
timestampInstalled: formatRFC3339(subMonths(now, 2)),
},
]);
await render(hbs`
`);
assert.dom('[data-test-line-chart]').exists('Chart is rendered');
assert
.dom('[data-test-line-chart="plot-point"]')
.exists({ count: this.dataset.length }, `renders ${this.dataset.length} plot points`);
assert
.dom(find(`[data-test-line-chart="upgrade-${this.dataset[2].month}"]`))
.hasStyle(
{ fill: 'rgb(253, 238, 186)' },
`upgrade data point ${this.dataset[2].month} has yellow highlight`
);
});
test('it renders tooltip', async function (assert) {
assert.expect(1);
const now = timestamp.now();
const tooltipData = [
{
month: format(subMonths(now, 4), 'M/yy'),
timestamp: formatRFC3339(subMonths(now, 4)),
clients: 4,
new_clients: {
clients: 0,
},
},
{
month: format(subMonths(now, 3), 'M/yy'),
timestamp: formatRFC3339(subMonths(now, 3)),
clients: 8,
new_clients: {
clients: 4,
},
},
{
month: format(subMonths(now, 2), 'M/yy'),
timestamp: formatRFC3339(subMonths(now, 2)),
clients: 14,
new_clients: {
clients: 6,
},
},
{
month: format(subMonths(now, 1), 'M/yy'),
timestamp: formatRFC3339(subMonths(now, 1)),
clients: 20,
new_clients: {
clients: 4,
},
},
];
this.set('dataset', tooltipData);
this.set('upgradeData', [
{
id: '1.10.1',
previousVersion: '1.9.2',
timestampInstalled: formatRFC3339(subMonths(now, 2)),
},
]);
await render(hbs`
`);
const tooltipHoverCircles = findAll('[data-test-hover-circle]');
assert.strictEqual(tooltipHoverCircles.length, tooltipData.length, 'all data circles are rendered');
// FLAKY after adding a11y testing, skip for now
// for (const [i, bar] of tooltipHoverCircles.entries()) {
// await triggerEvent(bar, 'mouseover');
// const tooltip = document.querySelector('.ember-modal-dialog');
// const { month, clients, new_clients } = tooltipData[i];
// assert
// .dom(tooltip)
// .includesText(
// `${formatChartDate(month)} ${clients} total clients ${new_clients.clients} new clients`,
// `tooltip text is correct for ${month}`
// );
// }
});
test('it fails gracefully when data is not formatted correctly', async function (assert) {
this.set('dataset', [
{
foo: 1,
bar: 4,
},
{
foo: 2,
bar: 8,
},
{
foo: 3,
bar: 14,
},
{
foo: 4,
bar: 10,
},
]);
await render(hbs`
`);
assert.dom('[data-test-line-chart]').doesNotExist('Chart is not rendered');
assert
.dom('[data-test-component="empty-state"]')
.hasText('No data to display', 'Shows empty state when time date is not formatted correctly');
});
test('it fails gracefully when upgradeData is an object', async function (assert) {
this.set('upgradeData', { some: 'object' });
await render(hbs`
`);
assert
.dom('[data-test-line-chart="plot-point"]')
.exists({ count: this.dataset.length }, 'chart still renders when upgradeData is not an array');
});
test('it fails gracefully when upgradeData has incorrect key names', async function (assert) {
this.set('upgradeData', [{ incorrect: 'key names' }]);
await render(hbs`
`);
assert
.dom('[data-test-line-chart="plot-point"]')
.exists({ count: this.dataset.length }, 'chart still renders when upgradeData has incorrect keys');
});
test('it renders empty state when no dataset', async function (assert) {
await render(hbs`
`);
assert.dom('[data-test-component="empty-state"]').exists('renders empty state when no data');
assert
.dom('[data-test-empty-state-subtext]')
.hasText(
`this is a custom message to explain why you're not seeing a line chart`,
'custom message renders'
);
});
test('it updates axis when dataset updates', async function (assert) {
const datasets = {
small: [
{
foo: '2020-04-01',
bar: 4,
month: '4/20',
},
{
foo: '2020-05-01',
bar: 8,
month: '5/20',
},
{
foo: '2020-06-01',
bar: 1,
},
{
foo: '2020-07-01',
bar: 10,
},
],
large: [
{
foo: '2020-08-01',
bar: 4586,
month: '8/20',
},
{
foo: '2020-09-01',
bar: 8928,
month: '9/20',
},
{
foo: '2020-10-01',
bar: 11948,
month: '10/20',
},
{
foo: '2020-11-01',
bar: 16943,
month: '11/20',
},
],
broken: [
{
foo: '2020-01-01',
bar: null,
month: '1/20',
},
{
foo: '2020-02-01',
bar: 0,
month: '2/20',
},
{
foo: '2020-03-01',
bar: 22,
month: '3/20',
},
{
foo: '2020-04-01',
bar: null,
month: '4/20',
},
{
foo: '2020-05-01',
bar: 70,
month: '5/20',
},
{
foo: '2020-06-01',
bar: 50,
month: '6/20',
},
],
};
this.set('dataset', datasets.small);
await render(hbs`
`);
assert.dom('[data-test-y-axis]').hasText('0 2 4 6 8 10', 'y-axis renders correctly for small values');
assert
.dom('[data-test-x-axis]')
.hasText('4/20 5/20 6/20 7/20', 'x-axis renders correctly for small values');
// Update to large dataset
this.set('dataset', datasets.large);
assert.dom('[data-test-y-axis]').hasText('0 5k 10k 15k', 'y-axis renders correctly for new large values');
assert
.dom('[data-test-x-axis]')
.hasText('8/20 9/20 10/20 11/20', 'x-axis renders correctly for small values');
// Update to broken dataset
this.set('dataset', datasets.broken);
assert.dom('[data-test-y-axis]').hasText('0 20 40 60', 'y-axis renders correctly for new broken values');
assert
.dom('[data-test-x-axis]')
.hasText('1/20 2/20 3/20 4/20 5/20 6/20', 'x-axis renders correctly for small values');
assert.dom('[data-test-hover-circle]').exists({ count: 4 }, 'only render circles for non-null values');
assert
.dom('[data-test-hover-circle="1/20"]')
.doesNotExist('first month dot does not exist because value is null');
assert
.dom('[data-test-hover-circle="4/20"]')
.doesNotExist('other null count month dot also does not render');
// Note: the line should also show a gap, but this is difficult to test for
});
});