Skip to content

Commit 8ae86cd

Browse files
committedNov 26, 2024
Add assertions
1 parent 7754d7a commit 8ae86cd

File tree

3 files changed

+87
-30
lines changed

3 files changed

+87
-30
lines changed
 

‎packages/host/app/components/operator-mode/profile/profile-subscription.gts

+24-12
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
import { fn } from '@ember/helper';
22

33
import { on } from '@ember/modifier';
4+
import Owner from '@ember/owner';
45
import { service } from '@ember/service';
56
import Component from '@glimmer/component';
67

7-
import { trackedFunction } from 'ember-resources/util/function';
8+
import { task } from 'ember-concurrency';
9+
10+
import window from 'ember-window-mock';
811

912
import {
1013
BoxelButton,
@@ -60,22 +63,25 @@ export default class ProfileSubscription extends Component<Signature> {
6063
<div class='buy-more-credits'>
6164
<span class='buy-more-credits__title'>Buy more credits</span>
6265
<div class='payment-links'>
63-
{{#each this.paymentLinks as |paymentLink|}}
64-
{{#if this.fetchPaymentLinks.isPending}}
65-
<LoadingIndicator />
66-
{{else}}
67-
<div class='payment-link'>
66+
{{#if this.fetchPaymentLinks.isRunning}}
67+
<LoadingIndicator />
68+
{{else}}
69+
{{#each
70+
this.billingService.paymentLinks
71+
as |paymentLink index|
72+
}}
73+
<div class='payment-link' data-test-payment-link={{index}}>
6874
<span><IconHexagon width='16px' height='16px' />
6975
{{paymentLink.creditReloadAmount}}</span>
7076
<BoxelButton
7177
@kind='secondary-light'
7278
@size='extra-small'
7379
{{on 'click' (fn this.pay paymentLink.url)}}
74-
data-test-buy-more-button
80+
data-test-pay-button={{index}}
7581
>Pay</BoxelButton>
7682
</div>
77-
{{/if}}
78-
{{/each}}
83+
{{/each}}
84+
{{/if}}
7985
</div>
8086
</div>
8187
</div>
@@ -103,6 +109,7 @@ export default class ProfileSubscription extends Component<Signature> {
103109
gap: var(--boxel-sp-xs);
104110
padding-left: var(--boxel-sp-sm);
105111
border-left: 5px solid #c6c6c6;
112+
min-height: 40px;
106113
}
107114
.credit-info__label {
108115
font: var(--boxel-font-xs);
@@ -148,16 +155,21 @@ export default class ProfileSubscription extends Component<Signature> {
148155
--icon-color: var(--boxel-teal);
149156
--boxel-loading-indicator-size: var(--boxel-icon-xs);
150157
}
158+
:deep(.boxel-loading-indicator) {
159+
width: 100%;
160+
text-align: center;
161+
}
151162
</style>
152163
</template>
153164

154165
@service private declare billingService: BillingService;
155166

156-
private get paymentLinks() {
157-
return this.fetchPaymentLinks.value ?? [];
167+
constructor(owner: Owner, args: any) {
168+
super(owner, args);
169+
this.fetchPaymentLinks.perform();
158170
}
159171

160-
private fetchPaymentLinks = trackedFunction(this, async () => {
172+
private fetchPaymentLinks = task(async () => {
161173
return await this.billingService.fetchPaymentLinks();
162174
});
163175

‎packages/host/app/services/billing-service.ts

+21-12
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { tracked } from '@glimmer/tracking';
55

66
import { dropTask } from 'ember-concurrency';
77

8+
import window from 'ember-window-mock';
89
import Stripe from 'stripe';
910

1011
import { SupportedMimeType } from '@cardstack/runtime-common';
@@ -31,7 +32,7 @@ interface PaymentLink {
3132

3233
export default class BillingService extends Service {
3334
@tracked private _subscriptionData: SubscriptionData | null = null;
34-
private _paymentLinks: PaymentLink[] | null = null;
35+
@tracked private _paymentLinks: PaymentLink[] | null = null;
3536

3637
@service private declare realmServer: RealmServerService;
3738
@service private declare network: NetworkService;
@@ -57,22 +58,30 @@ export default class BillingService extends Service {
5758

5859
async fetchPaymentLinks() {
5960
if (!this._paymentLinks) {
60-
let response = await stripe.paymentLinks.list();
61-
this._paymentLinks = response.data
62-
.filter((data) => data.metadata.credit_reload_amount)
63-
.map((data) => ({
64-
url: data.url,
65-
creditReloadAmount: Number(data.metadata.credit_reload_amount),
66-
}))
67-
.sort(
68-
(paymentLinkA, paymentLinkB) =>
69-
paymentLinkA.creditReloadAmount - paymentLinkB.creditReloadAmount,
70-
);
61+
await this.fetchPaymentLinksTask.perform();
7162
}
7263

7364
return this._paymentLinks;
7465
}
7566

67+
get paymentLinks() {
68+
return this._paymentLinks;
69+
}
70+
71+
private fetchPaymentLinksTask = dropTask(async () => {
72+
let response = await stripe.paymentLinks.list();
73+
this._paymentLinks = response.data
74+
.filter((data) => data.metadata.credit_reload_amount)
75+
.map((data) => ({
76+
url: data.url,
77+
creditReloadAmount: Number(data.metadata.credit_reload_amount),
78+
}))
79+
.sort(
80+
(paymentLinkA, paymentLinkB) =>
81+
paymentLinkA.creditReloadAmount - paymentLinkB.creditReloadAmount,
82+
);
83+
});
84+
7685
get subscriptionData() {
7786
return this._subscriptionData;
7887
}

‎packages/host/tests/acceptance/operator-mode-acceptance-test.gts

+42-6
Original file line numberDiff line numberDiff line change
@@ -867,6 +867,25 @@ module('Acceptance | operator mode tests', function (hooks) {
867867
});
868868

869869
test(`displays credit info in account popover`, async function (assert) {
870+
let countWindowOpenCalled = 0;
871+
let mockWindow = {
872+
closeCalled: false,
873+
close() {
874+
this.closeCalled = true;
875+
},
876+
};
877+
878+
const originalWindowOpen = window.open;
879+
window.open = (url, _target, _feature) => {
880+
assert.true(
881+
typeof url === 'string'
882+
? url.includes('stripe')
883+
: url?.href.includes('stripe'),
884+
);
885+
countWindowOpenCalled++;
886+
return mockWindow as unknown as Window;
887+
};
888+
870889
await visitOperatorMode({
871890
submode: 'interact',
872891
codePath: `${testRealmURL}employee.gts`,
@@ -901,19 +920,35 @@ module('Acceptance | operator mode tests', function (hooks) {
901920
assert.dom('[data-test-buy-more-credits]').hasNoClass('out-of-credit');
902921

903922
await click('[data-test-upgrade-plan-button]');
904-
assert.dom('[data-test-profile-popover]').doesNotExist();
905-
assert
906-
.dom('[data-test-boxel-card-container]')
907-
.hasClass('profile-settings');
908923

909-
await click('[aria-label="close modal"]');
910-
await click('[data-test-profile-icon-button]');
911924
assert.dom('[data-test-profile-popover]').exists();
912925
await click('[data-test-buy-more-credits] button');
913926
assert.dom('[data-test-profile-popover]').doesNotExist();
914927
assert
915928
.dom('[data-test-boxel-card-container]')
916929
.hasClass('profile-settings');
930+
assert.dom('[data-test-subscription-data="plan"]').hasText('Free');
931+
assert
932+
.dom('[data-test-subscription-data="monthly-credit"]')
933+
.hasText('1000 of 1000 left');
934+
assert
935+
.dom('[data-test-subscription-data="monthly-credit"]')
936+
.hasNoClass('out-of-credit');
937+
assert
938+
.dom('[data-test-subscription-data="additional-credit"]')
939+
.hasText('100');
940+
assert
941+
.dom('[data-test-subscription-data="additional-credit"]')
942+
.hasNoClass('out-of-credit');
943+
await waitFor('[data-test-payment-link]');
944+
assert.dom('[data-test-payment-link]').exists({ count: 3 });
945+
await click('[data-test-manage-plan-button]');
946+
await click('[data-test-pay-button]');
947+
assert.strictEqual(
948+
countWindowOpenCalled,
949+
3,
950+
'Correct number of times window.open was called',
951+
);
917952

918953
// out of credit
919954
await click('[aria-label="close modal"]');
@@ -986,6 +1021,7 @@ module('Acceptance | operator mode tests', function (hooks) {
9861021
.dom('[data-test-subscription-data="additional-credit"]')
9871022
.hasNoClass('out-of-credit');
9881023
assert.dom('[data-test-buy-more-credits]').hasNoClass('out-of-credit');
1024+
window.open = originalWindowOpen;
9891025
});
9901026
});
9911027
});

0 commit comments

Comments
 (0)
Failed to load comments.