import { module, test } from 'qunit'; import { setupRenderingTest } from 'ember-qunit'; import { click, fillIn, render } from '@ember/test-helpers'; import hbs from 'htmlbars-inline-precompile'; import contributors from '../../../fixtures/contributors'; import contributions from '../../../fixtures/contributions'; module('Integration | Component | contribution-list', function(hooks) { setupRenderingTest(hooks); test('it renders all contributions with grouped rows collapsed', async function(assert) { let kredits = this.owner.lookup('service:kredits'); kredits.set('contributors', contributors); this.set('fixtures', contributions); await render(hbs`{{contribution-list contributions=fixtures}}`); // 9 contributions: 2 groups (ids 1+3, 7+8) + 5 singletons = 7 top-level rows assert.equal(this.element.querySelectorAll('li').length, 7, '7 top-level rows when collapsed'); assert.equal(this.element.querySelectorAll('li.grouped').length, 2, '2 grouped headers'); assert.equal(this.element.querySelectorAll('li.group-item').length, 0, 'no expanded sub-items'); }); test('it renders filtered contributions', async function(assert) { let kredits = this.owner.lookup('service:kredits'); kredits.set('contributors', contributors); this.set('fixtures', contributions); await render(hbs`{{contribution-list contributions=fixtures showQuickFilter=true}}`); await fillIn('.filter-contributor select', '1'); // Contributor 1 is in ids 1, 2, 5, 6, 8. Grouped rows stay whole: id 1's // group (with id 3) and id 8's group (with id 7) show as grouped rows // because id 1 / id 8 match; ids 2, 5, 6 are singletons. 5 top-level rows. assert.equal(this.element.querySelectorAll('li').length, 5, 'select contributor'); await click('.filter-contribution-size input'); // Hide small (<=500): drops id 6 only. Grouped rows stay (matching items // are 1500/1500). 4 top-level rows. assert.equal(this.element.querySelectorAll('li').length, 4, 'hide small contributions'); await fillIn('.filter-contribution-kind select', 'dev'); // Kind dev (still filtered to contributor 1, hide small on): only groups // where a single item passes all three filters survive. Group {1,3}: id 1 // is contributor 1 + dev → included. Group {8,7}: id 8 is contributor 1 but // community; id 7 is dev but contributor 3 → no item passes both → excluded. // Singletons id 2 (ops), id 5 (design) → excluded. 1 top-level row. assert.equal(this.element.querySelectorAll('li').length, 1, 'select kind'); }); test('filtering by contributor keeps grouped rows whole', async function(assert) { let kredits = this.owner.lookup('service:kredits'); kredits.set('contributors', contributors); this.set('fixtures', contributions); await render(hbs`{{contribution-list contributions=fixtures showQuickFilter=true}}`); await fillIn('.filter-contributor select', '1'); // The first row is the group containing id 1 (contributor 1) and id 3 // (contributor 2) — it stays grouped, not collapsed to a singleton. const firstRow = this.element.querySelector('li'); assert.ok(firstRow.classList.contains('grouped'), 'first row is still grouped'); assert.equal(firstRow.querySelectorAll('.avatars img').length, 2, 'shows both contributors avatars'); }); test('grouped row expands on click to reveal sub-items', async function(assert) { let kredits = this.owner.lookup('service:kredits'); kredits.set('contributors', contributors); this.set('fixtures', contributions); await render(hbs`{{contribution-list contributions=fixtures}}`); assert.equal(this.element.querySelectorAll('li.group-item').length, 0, 'no sub-items when collapsed'); await click('.grouped:first-child'); assert.equal(this.element.querySelectorAll('li.group-item').length, 2, '2 sub-items when expanded'); assert.ok(this.element.querySelector('.grouped').classList.contains('expanded'), 'header has expanded class'); await click('.grouped:first-child'); assert.equal(this.element.querySelectorAll('li.group-item').length, 0, 'sub-items hidden when collapsed'); }); test('grouped row shows stacked avatars and single amount', async function(assert) { let kredits = this.owner.lookup('service:kredits'); kredits.set('contributors', contributors); this.set('fixtures', contributions); await render(hbs`{{contribution-list contributions=fixtures}}`); const firstGroup = this.element.querySelector('.grouped'); // Group ids 1+3 → 2 contributors → 2 avatars, no overflow assert.equal(firstGroup.querySelectorAll('.avatars img').length, 2, '2 avatar images'); assert.equal(firstGroup.querySelectorAll('.avatar-overflow').length, 0, 'no overflow bubble for 2 contributors'); // Single amount (first item's amount = 1500, not the sum) assert.equal(firstGroup.querySelector('.amount').textContent.trim(), '1500', 'shows single contribution amount'); }); test('auto-expands when selectedContributionId is a group child', async function(assert) { let kredits = this.owner.lookup('service:kredits'); kredits.set('contributors', contributors); this.set('fixtures', contributions); this.set('selectedId', 3); await render(hbs`{{contribution-list contributions=fixtures selectedContributionId=selectedId}}`); assert.equal(this.element.querySelectorAll('li.group-item').length, 2, 'group auto-expanded'); const selectedChild = this.element.querySelector('.group-item.selected'); assert.ok(selectedChild, 'selected child has selected class'); assert.equal(selectedChild.dataset.contributionId, '3', 'correct child is selected'); }); });