import { module, test } from 'qunit'; import { setupTest } from 'ember-qunit'; import contributors from '../../fixtures/contributors'; import contributions from '../../fixtures/contributions'; import ContributionModel from 'kredits-web/models/contribution'; import processContributionData from 'kredits-web/utils/process-contribution-data'; module('Unit | Service | kredits', function(hooks) { setupTest(hooks); test('#contributionsConfirmed', function(assert) { let service = this.owner.lookup('service:kredits'); service.set('contributions', contributions); service.set('currentBlock', 1023); const items = service.contributionsConfirmed; assert.equal(items.length, 5); }); test('#contributionsUnconfirmed', function(assert) { let service = this.owner.lookup('service:kredits'); service.set('contributions', contributions); service.set('currentBlock', 1023); const items = service.contributionsUnconfirmed; assert.equal(items.length, 3); }); test('#kreditsByContributor', function(assert) { let service = this.owner.lookup('service:kredits'); service.set('contributors', contributors); service.set('contributions', contributions); service.set('currentBlock', 1023); const kreditsByContributor = service.kreditsByContributor; assert.equal(kreditsByContributor.length, 3, 'includes all contributors with confirmed kredits'); const c1 = kreditsByContributor.find(k => k.contributor.id == 1); assert.equal(c1.amountConfirmed, 11500, 'correct amount confirmed'); assert.equal(c1.amountUnconfirmed, 1500, 'correct amount unconfirmed'); assert.equal(c1.amountTotal, 13000, 'correct amount total'); const c2 = kreditsByContributor.find(k => k.contributor.id == 2); assert.equal(c2.amountConfirmed, 3000, 'correct amount confirmed'); assert.equal(c2.amountUnconfirmed, 0, 'correct amount unconfirmed'); assert.equal(c2.amountTotal, 3000, 'correct amount total'); const c3 = kreditsByContributor.find(k => k.contributor.id == 3); assert.equal(c3.amountConfirmed, 0, 'correct amount confirmed'); assert.equal(c3.amountUnconfirmed, 5000, 'correct amount unconfirmed'); assert.equal(c3.amountTotal, 5000, 'correct amount total'); }); test('#contributorsSorted', function(assert) { let service = this.owner.lookup('service:kredits'); service.set('contributors', contributors); assert.ok(service.contributorsSorted instanceof Array, 'is an array'); assert.equal(service.contributorsSorted[1].name, 'Manuel', 'sorts by name'); }); test('#contributionsGrouped groups contributions sharing a url', function(assert) { let service = this.owner.lookup('service:kredits'); service.set('contributors', contributors); service.set('contributions', contributions); const grouped = service.contributionsGrouped; // 9 contributions, with ids 1+3 sharing a url and ids 7+8 sharing a url, // so 7 groups total (2 grouped + 5 singletons). assert.equal(grouped.length, 7, 'produces one group per unique key plus singletons'); const ghGroup = grouped.findBy('groupId', 'https://github.com/67P/kredits-contracts/pull/196'); assert.ok(ghGroup, 'github url group exists'); assert.ok(ghGroup.isGrouped, 'github group is flagged as grouped'); assert.equal(ghGroup.items.length, 2, 'github group has two contributions'); assert.deepEqual(ghGroup.contributorIds, [1, 2], 'github group lists both contributor ids'); assert.equal(ghGroup.contributors.length, 2, 'github group resolves both contributors'); assert.equal(ghGroup.totalAmount, 3000, 'github group sums amounts (1500 + 1500)'); assert.equal(ghGroup.kind, 'dev', 'github group takes kind from first item'); assert.equal(ghGroup.url, 'https://github.com/67P/kredits-contracts/pull/196'); const giteaGroup = grouped.findBy('groupId', 'https://gitea.kosmos.org/kredits/kredits-web/issues/231'); assert.ok(giteaGroup, 'gitea url group exists'); assert.ok(giteaGroup.isGrouped, 'gitea group is flagged as grouped'); assert.deepEqual(giteaGroup.contributorIds, [3, 1], 'gitea group lists both contributor ids'); assert.equal(giteaGroup.totalAmount, 6500, 'gitea group sums amounts (5000 + 1500)'); }); test('#contributionsGrouped treats manual contributions without url as singletons', function(assert) { let service = this.owner.lookup('service:kredits'); service.set('contributors', contributors); service.set('contributions', contributions); const grouped = service.contributionsGrouped; const singletons = grouped.filterBy('isGrouped', false); // 5 contributions without a url: ids 2, 4, 5, 6, 9 assert.equal(singletons.length, 5, 'one singleton group per url-less contribution'); singletons.forEach(g => { assert.equal(g.items.length, 1, 'singleton group has exactly one item'); assert.notOk(g.groupId, 'singleton group has a null/empty groupId'); }); }); test('#siblingContributions returns co-contributor contributions for the same url', function(assert) { let service = this.owner.lookup('service:kredits'); service.set('contributors', contributors); service.set('contributions', contributions); const c1 = contributions.findBy('id', 1); const siblings = service.siblingContributions(c1); assert.equal(siblings.length, 1, 'contribution 1 has one sibling'); assert.equal(siblings[0].id, 3, 'the sibling is contribution 3'); }); test('#siblingContributions returns empty for manual contributions', function(assert) { let service = this.owner.lookup('service:kredits'); service.set('contributors', contributors); service.set('contributions', contributions); const c2 = contributions.findBy('id', 2); assert.deepEqual(service.siblingContributions(c2), [], 'no siblings for url-less contribution'); }); test('#siblingContributions returns empty for null contribution', function(assert) { let service = this.owner.lookup('service:kredits'); service.set('contributors', contributors); service.set('contributions', contributions); assert.deepEqual(service.siblingContributions(null), [], 'no siblings for null'); }); test('#kreditsByContributor ignores unconfirmed contributions for contributors that are not loaded', function(assert) { let service = this.owner.lookup('service:kredits'); service.set('contributors', contributors); // Contribution referencing a contributor that is not in the contributors // collection (e.g. its IPFS profile failed to deserialize). The dashboard // must not throw when computing the toplist. const orphanAttrs = { id: 99, contributorId: 999, confirmedAt: 2000, claimed: false, vetoed: false, amount: 7000, kind: 'dev' }; const orphan = ContributionModel.create(processContributionData(orphanAttrs)); orphan.set('contributor', undefined); service.set('contributions', [...contributions, orphan]); service.set('currentBlock', 1023); let kreditsByContributor; try { kreditsByContributor = service.kreditsByContributor; } catch (e) { assert.ok(false, `did not expect kreditsByContributor to throw: ${e.message}`); return; } assert.ok(kreditsByContributor, 'computes without throwing'); assert.notOk(kreditsByContributor.findBy('contributor', undefined), 'no entry for the missing contributor'); assert.notOk(kreditsByContributor.find(k => k.contributor && k.contributor.id === 999), 'orphan contributor id is absent from the toplist'); }); });