Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/e2e-testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ The join form specs (the table below) are listed with their test counts. The set
| Membership Plans | `membership-plans.spec.ts` | Every setting. Plans: added, edited and removed, stored under their ID, offered on join forms without their own plans; each plan field's effect on the form and on joins (`/join`, including the custom-amount minimum); at least one plan required, and Name and Price required by the page (not by the plugin: JOIN-169); each frequency and currency set up in Stripe (fake API). Tags: defaults; on a join, the plan's Add Tags added and the lapsed, cancelled, lapsing and other plans' tags removed; lapsed, cancelled and lapsing tags applied by Stripe webhook events; tier changes swap plan tags; no tags while another subscription is active (fake Mailchimp). Known problems: JOIN-166 (duplicate Stripe prices for prices with pence), JOIN-169 (Name and Price not checked by the plugin). Open question: JOIN-170 (removed plans stay joinable). |
| Theme | `theme.spec.ts` | Every setting: colour defaults, each colour reaching the form's styles (the primary colour on its buttons), custom CSS applied. |
| Copy | `copy.spec.ts` | Every setting: each one's default (or none), the fallbacks for blank sidebar, stage label and joining verb, and where each shows (details, plan and bank-details steps, confirmation step, sidebar). Known problems: JOIN-162 (Home Address Copy never shows), JOIN-163 (day-of-month copy unused), JOIN-164 (organisation details marked required but not enforced). |
| Integrations | | Not yet. What Mailchimp, Action Network and Zetkin receive on a join will be covered here. |
| Integrations | `integrations-crm.spec.ts`, `integrations-payments.spec.ts`, `integrations-logging.spec.ts` | Every setting. Joins through the real form reach Zetkin (join form, or the API with OAuth; sandbox/live), Mailchimp, Action Network, Auth0 and the join-complete webhook with the credentials and IDs set here; the step webhook; webhook URLs never reach the form. Stripe direct debit and Direct Debit only (the payment methods Stripe's fields are set up with), the subscriptions download; GoCardless sandbox/live; Chargebee hosted pages; getAddress.io and Ideal Postcodes lookups and their key checks; Sentry, Google Cloud Logging and Loggly receiving the plugin's logs (all fake API). Known problem: JOIN-167 (subscriptions download breaks with no Stripe invoices). |
Comment thread
conatus marked this conversation as resolved.
Resolved
| Logging | | Not yet |
| Debug | | Not yet |

Expand Down
3 changes: 3 additions & 0 deletions packages/join-e2e/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ services:
- api.postcodes.io
- api.getaddress.io
- api.ideal-postcodes.co.uk
- logs-01.loggly.com
- sentry.e2e.example
- logging.googleapis.com

db:
image: mariadb:11.4
Expand Down
32 changes: 16 additions & 16 deletions packages/join-e2e/fake-api/certs/ca.crt
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
-----BEGIN CERTIFICATE-----
MIIDPzCCAiegAwIBAgIUL1NIuEmpA0RWqABA149MgtVN6S8wDQYJKoZIhvcNAQEL
MIIDPzCCAiegAwIBAgIUPHRrwi26P4sc3ZGz0uZqZnIYAQcwDQYJKoZIhvcNAQEL
BQAwLjEsMCoGA1UEAwwjSm9pbiBFMkUgdGVzdCBDQSAobm90IGZvciByZWFsIHVz
ZSkwIBcNMjYxMDIzMTc1NDA2WhgPMjEyNjA5MjkxNzU0MDZaMC4xLDAqBgNVBAMM
ZSkwIBcNMjYxMDI0MTYyODE2WhgPMjEyNjA5MzAxNjI4MTZaMC4xLDAqBgNVBAMM
I0pvaW4gRTJFIHRlc3QgQ0EgKG5vdCBmb3IgcmVhbCB1c2UpMIIBIjANBgkqhkiG
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5MZLGxuo1wv3q/KZlHPYs1msn5HP9/MS93px
sfubWlrPxW0CWIxTMtv98kyeNggsQ6pqbFdpLSpDrMI2L4+OTYwTwV+LrzV4neSm
GXHVAqB93QLaHLQwdWdjiGJ8vaX069c8LzNvnZb8KVf7MtLWX2MsRNYJtXCCtxuT
wV3RZDQs4TNOqGikoyRg/JNCxkgBPHNSm7ptCj3rj2rbQGDM7nu1skBzH3L6xKiA
QGiYb+vNDWcdK4I38cA8BbQdS+DXvHIf+Y6Qlq8h6esI7a8pnbhm60RIHNvsEdFq
qPFPowydKT8RyjABZHnajyYXyv3PGeGjXC/hRRTsaJg54GUxiwIDAQABo1MwUTAd
BgNVHQ4EFgQU6xlodRtSMB1hTbE+cfkyMBWT2QUwHwYDVR0jBBgwFoAU6xlodRtS
MB1hTbE+cfkyMBWT2QUwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC
AQEAGjcNh/YqYwRw5w+ilPybR9DHl0OG7/k7VXrGRqml0QvbDD1h4jR4Hqz2AwXr
HFt6LdnXOvlVk+u6t6FvNflFu059sNeJx7b5FRBoTvrjNZfFehoKD5NkuamGGWdk
XIEeG0NIBaYF4DYu9qK1jKL1DcpM4lFOfy55pcNEqyBEyULmpJVYhBAsddb4gtuU
oZHM/rZdp/k463E53SHUPMD3arh3CDcq+JLSr3uDs7nRex7HfY0U7DFd4DlcuuH/
oWnAGLOcb17zzahyAdsmCetiGuzAp7SU7p6DBLnT3Yr5i/CjhWKoKCDqAIaybIgw
dIdD1NBq1DZNpTYgPl/dvaa5fg==
9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqPWqiTOYaSUhsqffO7PkmfjCRl6+iluKXe/Y
oPG3ZhGVSNzBaoKaYOgzEm9LGH9G7XheqPaYBTpfsTq653uBXG9xN9XP+vJYi1tH
bDKvgOd8W5sus0XaBq/pNz60kWgc76RkMXRJA31isTEF5JWFZqlpPIBQyMfmuXFw
9Gw456A0t5HfnjoSOufrtWMMxyN+KBh6g0aVieS50ZqAJATrhK6/ugM1DlzTY3iI
IGTFi2wbafnxvBeCNn0tsTyi6sKXgfNh8zhBebHAjByzEfbWuTly1kdccBso+4pK
y37H8lpyu1pWZLnkga6WPL3lbFAnsOMQX1e/ltYpoETKUpRQIQIDAQABo1MwUTAd
BgNVHQ4EFgQUZ/8fKXjIKwXYoj7HJRLG9nAeF84wHwYDVR0jBBgwFoAUZ/8fKXjI
KwXYoj7HJRLG9nAeF84wDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC
AQEAIOREepSRwdWrmZnjtwfrEeMBFBjo4AVhEbH5kYeOXyE6Bm7KgXTYJpcbA/cJ
VMmigfzDXPRMnPF6yuCgb3a5bndLmXSYJ8koAFg3lwUQPMoacTS83iyPtECr3H6l
hyggkh6XIR53kQE8jdtqJOa+HZFByQYiwhShMGoRP13wYILHrl0VAyZgUpvwy564
mBawUjbYJ6mkAwvoPb3YtOapSk9HpSY7q4AvvNa0rVi0kA3HDo/9/mXbZUq8zV8l
+9S1LW2/bWHFL1HYuEdoHhV5znoGwLPdx0PLsBplJC7E6IYyYQXyNVQQ5pW2aPnF
RmV3DFCaaj2w/5D9ef2c8HogTA==
-----END CERTIFICATE-----
3 changes: 3 additions & 0 deletions packages/join-e2e/fake-api/certs/san.cnf
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,6 @@ DNS.10 = api.postcodes.io
DNS.11 = api.getaddress.io
DNS.12 = api.ideal-postcodes.co.uk
DNS.13 = fake-api
DNS.14 = logs-01.loggly.com
DNS.15 = sentry.e2e.example
DNS.16 = logging.googleapis.com
47 changes: 24 additions & 23 deletions packages/join-e2e/fake-api/certs/server.crt
Original file line number Diff line number Diff line change
@@ -1,26 +1,27 @@
-----BEGIN CERTIFICATE-----
MIIETTCCAzWgAwIBAgIUcBvmd6AYMCx4hAsRuJYvExc18BUwDQYJKoZIhvcNAQEL
MIIEjzCCA3egAwIBAgIUAJw+ei4n8CYxLloWgV0WE8fGUH0wDQYJKoZIhvcNAQEL
BQAwLjEsMCoGA1UEAwwjSm9pbiBFMkUgdGVzdCBDQSAobm90IGZvciByZWFsIHVz
ZSkwIBcNMjYxMDIzMTc1NDA2WhgPMjEyNjA5MjkxNzU0MDZaMBMxETAPBgNVBAMM
CGZha2UtYXBpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAreVk2RGX
irbBcE/J6YDanGGDwf404Lh9ni6Akw2zEANeVLxqvKiyi5l8wK1q+ah3J2jqo/LU
KrD65ZuhscZW5V+t9w/KqTkOE/4O76s3wJB8Y4sQcUuW4XtV/Wd028gZORu/DMp9
A1lK7ysqtuu/6K1D1/8evI6LsMNjrQshh3FXcJiUhcrfgrmM8lWVQE652KJIeRTi
iKQm9Xiwo8+Pj632bbmTfvCA6yLHrhOaLS9OB14XSjzzXSoxqLTLP9UTA6GvMLGi
FIlzl/ch8ZlnI9t/37JiEhBY2QzaEymKl2yLNcgG2YCQx71T8xAuuwu7Yy2E/A4k
C2o/LQcp2iJPowIDAQABo4IBejCCAXYwggEFBgNVHREEgf0wgfqCDmFwaS5zdHJp
cGUuY29tghFhY3Rpb25uZXR3b3JrLm9yZ4ILYXBpLnpldGsuaW6CEmFwaS5kZXYu
emV0a2luLm9yZ4IVdXMxLmFwaS5tYWlsY2hpbXAuY29tghBlMmUuZXUuYXV0aDAu
Y29tghJhcGkuZ29jYXJkbGVzcy5jb22CGmFwaS1zYW5kYm94LmdvY2FyZGxlc3Mu
Y29tghFlMmUuY2hhcmdlYmVlLmNvbYIQYXBpLnBvc3Rjb2Rlcy5pb4IRYXBpLmdl
dGFkZHJlc3MuaW+CGWFwaS5pZGVhbC1wb3N0Y29kZXMuY28udWuCCGZha2UtYXBp
MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMB0G
A1UdDgQWBBRmOT+xWfG1qKOcrTEPx4PG5jjkwzAfBgNVHSMEGDAWgBTrGWh1G1Iw
HWFNsT5x+TIwFZPZBTANBgkqhkiG9w0BAQsFAAOCAQEAM0haZ0adhRNvYMHkNm3B
IH614SRIsOlFt2SUYi33DYIy0Im0Mk3BGozgx/zY2/8LUu6mon47aKjJJpP922ew
MzzswMoAM7FnKiN0DV9asfsmCH8OeePjFHde4VWU6elTQ2Tb5Lmg0Tqafaew4sB6
xFe4usEl3AIaYtoZ6MULdsdNOXF42M4xlNp2l7uMcJT1IYQODxByJ1vd40k0q1Uz
uZx4qiRsF7HqV4q2/emjUu/67R871J5uM8aKxvRS2YLjuP2JruTOnjSQbJf1js60
PcGGWPREVvveXSLJiwD9DpXHjApKTZjMj7lk5fcGYe+Ka0CDxmhHhewiGiblRjcJ
YA==
ZSkwIBcNMjYxMDI0MTYyODE2WhgPMjEyNjA5MzAxNjI4MTZaMBMxETAPBgNVBAMM
CGZha2UtYXBpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA08Bmq+l4
O2WBv8ff6OoowzVJynaoeCdh+jBk7vQYqZ+/Qh+lQVwZLTMc0xPjYm/kss16DfyQ
uOBnkEmDyIjLhhxudq5kHTR7b+Fp6tVoM9UEBjtDZlnlL8Q+kyvAcVMZiO9ACOut
i5Ox9AhgnSCPG0LlxuNvMKNLF8RzYab46oS1lhSfsb54C5MV7MOB8gfut5c21EhW
hLYi8+ypzDyULnltOJBAQESyr3SsQCvGa6fkSnFlq+A/kaeGK4ioCiMkcb3DPkYn
h3v8ss+pllLFKcSuWkw6rve2GTbl0Qhn5MlbpXst3ChgzNrqnz1QfFEOAWF0yRjn
i2sjhwVYwJ1GzQIDAQABo4IBvDCCAbgwggFHBgNVHREEggE+MIIBOoIOYXBpLnN0
cmlwZS5jb22CEWFjdGlvbm5ldHdvcmsub3JnggthcGkuemV0ay5pboISYXBpLmRl
di56ZXRraW4ub3JnghV1czEuYXBpLm1haWxjaGltcC5jb22CEGUyZS5ldS5hdXRo
MC5jb22CEmFwaS5nb2NhcmRsZXNzLmNvbYIaYXBpLXNhbmRib3guZ29jYXJkbGVz
cy5jb22CEWUyZS5jaGFyZ2ViZWUuY29tghBhcGkucG9zdGNvZGVzLmlvghFhcGku
Z2V0YWRkcmVzcy5pb4IZYXBpLmlkZWFsLXBvc3Rjb2Rlcy5jby51a4IIZmFrZS1h
cGmCEmxvZ3MtMDEubG9nZ2x5LmNvbYISc2VudHJ5LmUyZS5leGFtcGxlghZsb2dn
aW5nLmdvb2dsZWFwaXMuY29tMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgWgMBMGA1Ud
JQQMMAoGCCsGAQUFBwMBMB0GA1UdDgQWBBTcS2OCMyXcbcGJgNlCf1iF60xYXDAf
BgNVHSMEGDAWgBRn/x8peMgrBdiiPsclEsb2cB4XzjANBgkqhkiG9w0BAQsFAAOC
AQEAo8x09RNAfZjFdFfTOtPzjA72bybjc9YNQcsqYX3C8qtRRnf8KhDxSekGiPKF
1R/9Dj9qkj7Gk7nPHZm0bqbWlAtrPqrdSwnILhegWj7qgxg5lWotxNGbcs8dHHtC
VoG13Pasaz+ALgak9dIsTOA8D2zvjAR6iy+yH0Ro0eI81P4deDqTE/KzPCS6gYYb
S4c66mTeZwsyOY5Nmgzms3vzvcaQeASdLTOQiKkj6T7Sl646n6AZsZIJVmDlt4Ta
7l+x+PsEejY+xuE4XyNP0V0IsWF5Ewlohh3/vbb1kgwLh6n8befRGrE5GD3r1W/8
p89Oh7rsu1AiOAVlsQ+if7W3yQ==
-----END CERTIFICATE-----
52 changes: 26 additions & 26 deletions packages/join-e2e/fake-api/certs/server.key
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCt5WTZEZeKtsFw
T8npgNqcYYPB/jTguH2eLoCTDbMQA15UvGq8qLKLmXzArWr5qHcnaOqj8tQqsPrl
m6GxxlblX633D8qpOQ4T/g7vqzfAkHxjixBxS5bhe1X9Z3TbyBk5G78Myn0DWUrv
Kyq267/orUPX/x68jouww2OtCyGHcVdwmJSFyt+CuYzyVZVATrnYokh5FOKIpCb1
eLCjz4+PrfZtuZN+8IDrIseuE5otL04HXhdKPPNdKjGotMs/1RMDoa8wsaIUiXOX
9yHxmWcj23/fsmISEFjZDNoTKYqXbIs1yAbZgJDHvVPzEC67C7tjLYT8DiQLaj8t
BynaIk+jAgMBAAECggEASIz4vsGiroph+SgozuVmD7F1haW3zPvb2PeAyBmCmA83
t3WmuJBPcYO3czHG/GMnV0dkAcPJdghBnTMJyoA799Wr4HRzspdtwrSP6blO+OWv
J964nPQS/n71GNSlgh6hO1zSoBUJBDEoXNFvMEL6XaqQMBkt6zAzoqtaNjN7KSTV
qfPyySMcnRJNHZGsSz8i4dekGZDUSwUV7u7kjmp2vlL5vo6T6tlY2JqHYRcm/qdl
GqI6JuH2fFmaLDlP2eyUu3Judqoq0PrwMgcEVz0Rtg7szEUcHrZg6O7YVVWVCyuS
+nC9yPtmbs1oyiXXQsKdItZiy5LwdzuGKXXrXw7WHQKBgQDe7ioZzHhQS39hg87o
YJQJdtlyTemgFywjtItWeX2Arq2n1nj4BioxJlvtEMXuFntYqUgJSOOB2m0n2k2v
duT7EUrON6+xcoHaGDaoT9qZHAzEr5OQb+dJmTUlWWDuU5xGGeBwFmIboO/2vNeS
E9/tqo9L2VU5P9WV2YPHH+pxxQKBgQDHsSQeVPSFzfLw6UvwiMrco8SdU15TOjFF
7hUzNESq/qo3WPuNiAiNDE8frWqVXzMRpbeYpujAFZd+XUONjI29z8CBTbcrZYjp
PKW1VxLn5gL1MCsGModdRnupzp8DVPvRuQhG1wgfqKLtP0wMvhLPkOpO24V5LokL
FRwnaP/aRwKBgQCIdHm6ruiaJYxD8T1OCgezP1dcWwp83pI7DMEZXmYOxV0wVdxX
3NYonZU5J8IvuP0pSPz6Ce6QRlX4Rey1UW5Zq70BOx7E3BVVnOqf3bktbPj3z4zg
pU6KQ0g/o1TsrKsEUcSKd3j39mvLuM2u8ZFo1bS+tbovv74J6kl6MjP8DQKBgH1B
q7oq58YWTNC4RZ327+g+AVH9vSjPU6DdmgaoPnpTi0l0UzWPom12zxq7mCNht5LW
M7dY2p3B7Wih74GWLEJnUgTJTp+17I8AL6DzoTQ8npZVRGd6wlXLpD37ENryL5J5
Uau9rabODIRsM7O6deokqBQWtj4w5l1BPIur3PB5AoGAYSXUMSGROOwFsJBWMyV0
Zkki7WTEqtkWD2WA4sggmxQw9jtbuiud558v6BT8RwbolUWICeNlfae0sxNNhMOV
9vQTeemYjZIDTaK8iJ7RdEqoLl27SjhmPsnXdn4+eunBEBUahs2U3QtAJ0SxLSlU
W8tmx1Coy7OXOWnP/jc1PoA=
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDTwGar6Xg7ZYG/
x9/o6ijDNUnKdqh4J2H6MGTu9Bipn79CH6VBXBktMxzTE+Nib+SyzXoN/JC44GeQ
SYPIiMuGHG52rmQdNHtv4Wnq1Wgz1QQGO0NmWeUvxD6TK8BxUxmI70AI662Lk7H0
CGCdII8bQuXG428wo0sXxHNhpvjqhLWWFJ+xvngLkxXsw4HyB+63lzbUSFaEtiLz
7KnMPJQueW04kEBARLKvdKxAK8Zrp+RKcWWr4D+Rp4YriKgKIyRxvcM+RieHe/yy
z6mWUsUpxK5aTDqu97YZNuXRCGfkyVuley3cKGDM2uqfPVB8UQ4BYXTJGOeLayOH
BVjAnUbNAgMBAAECggEAHy+S73avEnBcr5YMUA1Me5N5jqvzG98Q+vvtoZOpnjG8
xUxL1lhuDM4eTKf9MR4xnHPOqgisd8308rchBYPAFbxSOIBuli6Ij22vX7qWYivZ
L+HCh2xt6J8KaDplWUtX02cJE0dCg+/4oWwqbnnBGc68cJJGae9iu9le9N7WghNM
0ho819L/zQdWBjoHyAhiBARKBXCmRSTl7RFa3+6HoAL4TO/s0Eya8xOs27eYuRto
6h6uQklDSEDFHkQkK5NrVsLNsMtidITO7wxfUhUuuhbz7HVf/JkqsakreyaYTH8H
feJb1CVkzn9YsxU0hi1TxTj7nuqUJB2+uMC8AlAwMQKBgQD0T/YAzX/ElSrbGtQV
zD1rmB1Mpt8DlkVc3341cSiFVxUlV0LGdjYwgWhiahoJt+iMJUHvMLcTZgXp+zzW
OVCbGTv2cEpZ2Jf3iOiepudsGFGLOvR0hZ8ACrbmB3HqVZ2MCP+ZeX8YXcy9JoEL
UG9m7QoAh47TMKiYFgcIMozwJwKBgQDd4azrAs25FayUAIIYLJObucdp+O5e+nNz
YcqmZaZ6CHGItGt0Der81KYfoLFk1txA+gRF+K4rmYqNQVf0nxN+XET/UKkSU8b3
KdCYL0X7aIG5eGz7DJCj8i1Svi5Snbk7YGK1a285sJ29zGQ5aV2fX4p2RkFTTTx5
qGNLRo116wKBgBSU2+OLbFUSP+7/XpiLgS0cPnOjpyv1L9i4FzjHVKOPB4ACzuRL
Nxt0+2c3CwSAkr2jsd9FmlavBJaGjMR7RZgbUxrasNjKz1qSFQ6wftRzZAM3rzpV
u2RUgr30KJuWJNSUOXwjaRqTZFkW8k4Ss5/XHj2XLegKtFlDmcoOACOHAoGBAJ5W
Xb+X0Jc0EGPNuQjnRq7qdJP7QKAmuhysvKDiCVssi1iy57t58ydZ2PLZCb6cVbFI
uaP1QtV6TJVg/BNlMdQKpHJObVjW0DWxcVoo4hf3DBv/BEZjQRS9zfouHYB3bagh
sE8my8ivcOHw6dTOjDEfTP/6QsPfajinIbSmNGzhAoGABpB2U3DW2E95HXIPbRtV
CwwSqn4iLbCinJjK4LjNo6m3XsTS1bdKkzPtymin+HCvatBCWpIxj1KGRB2GcQ+l
nQr8fNPLRnj+8aNN43a5+wqp67rqc7JItwxTUWtYztAetKTACU4ytFiCSAATzR+S
+o6ztFhJ26HlF4fNRi6S5v0=
-----END PRIVATE KEY-----
57 changes: 54 additions & 3 deletions packages/join-e2e/fake-api/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,20 @@ const fs = require('fs');
const http = require('http');
const https = require('https');
const path = require('path');
const zlib = require('zlib');
const { URL } = require('url');

let requests = [];
let overrides = [];
let stripe = freshStripe();
let zetkin = freshZetkin();

function freshStripe() {
return { counter: 0, objects: { products: [], prices: [], customers: [], subscriptions: [] } };
return { counter: 0, objects: { products: [], prices: [], customers: [], subscriptions: [], invoices: [] } };
}

function freshZetkin() {
return { counter: 0, tags: [] };
}

function parseBody(raw, contentType) {
Expand Down Expand Up @@ -90,7 +96,7 @@ function fakeStripe(method, url, body) {
const [, type, idOrAction] = match;
const store = stripe.objects[type];
if (!store) return null;
const prefix = { products: 'prod', prices: 'price', customers: 'cus', subscriptions: 'sub' }[type];
const prefix = { products: 'prod', prices: 'price', customers: 'cus', subscriptions: 'sub', invoices: 'in' }[type];

if (method === 'GET' && idOrAction === 'search') {
const query = url.searchParams.get('query') || '';
Expand Down Expand Up @@ -125,6 +131,33 @@ function fakeStripe(method, url, body) {
return null;
}

/**
* A tiny in-memory Zetkin (api.zetk.in and api.dev.zetkin.org): enough for
* the plugin's OAuth sign-in, adding a person and tagging them.
*/
function fakeZetkin(method, url, body) {
const path = url.pathname.replace(/^\/v1/, '');
if (method === 'POST' && path === '/oauth/token') {
return { status: 200, body: { access_token: 'e2e-zetkin-access-token', token_type: 'bearer' } };
}
if (method === 'POST' && /^\/orgs\/[^/]+\/people$/.test(path)) {
return { status: 200, body: { data: { id: 4242, ...body } } };
}
if (/^\/orgs\/[^/]+\/people\/tags$/.test(path)) {
if (method === 'GET') return { status: 200, body: { data: zetkin.tags } };
if (method === 'POST') {
zetkin.counter += 1;
const tag = { id: zetkin.counter, title: body && body.title };
zetkin.tags.push(tag);
return { status: 200, body: { data: tag } };
}
}
if (/^\/orgs\/[^/]+\/people\/[^/]+\/tags\/[^/]+$/.test(path)) {
return { status: 200, body: { data: {} } };
}
return null;
}

function respond(host, method, url, body) {
const override = overrides.find(
(rule) =>
Expand All @@ -137,6 +170,13 @@ function respond(host, method, url, body) {
const result = fakeStripe(method, url, body);
if (result) return result;
}
if (host === 'api.zetk.in' || host === 'api.dev.zetkin.org') {
const result = fakeZetkin(method, url, body);
if (result) return result;
}
if (host.endsWith('.auth0.com') && method === 'POST' && url.pathname === '/oauth/token') {
return { status: 200, body: { access_token: 'e2e-auth0-access-token', token_type: 'Bearer', expires_in: 86400 } };
}
return { status: 200, body: {} };
}

Expand All @@ -146,7 +186,17 @@ function handleService(request, response) {
request.on('end', () => {
const host = (request.headers.host || '').split(':')[0];
const url = new URL(request.url, `https://${host}`);
const raw = Buffer.concat(chunks).toString('utf8');
let buffer = Buffer.concat(chunks);
// Sentry, for one, gzips what it sends. A body that won't unzip is
// recorded as it came, rather than crashing the fake.
if (request.headers['content-encoding'] === 'gzip') {
try {
buffer = zlib.gunzipSync(buffer);
} catch (error) {
console.error(`Could not gunzip a request to ${host}${request.url}: ${error.message}`);
}
}
const raw = buffer.toString('utf8');
const body = parseBody(raw, request.headers['content-type']);
requests.push({
time: new Date().toISOString(),
Expand Down Expand Up @@ -186,6 +236,7 @@ function handleControl(request, response) {
requests = [];
overrides = [];
stripe = freshStripe();
zetkin = freshZetkin();
return send(200, { ok: true });
}
if (request.method === 'POST' && request.url === '/overrides') {
Expand Down
4 changes: 2 additions & 2 deletions packages/join-e2e/tests/settings/copy.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
JoinSettingsPage,
MULTI_CURRENCY_PAGE,
STANDARD_JOIN_PAGE,
continueToPlans,
expect,
getSetting,
getSettings,
Expand All @@ -27,8 +28,7 @@ const details = (page: Page) => page.locator('form.form-content').first();
/** From the details step to the plan step. */
async function goToPlans(page: Page, url = STANDARD_JOIN_PAGE) {
await openJoinForm(page, url);
await page.locator(CONTINUE).click();
await page.waitForSelector('[role="radiogroup"]');
await continueToPlans(page);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion packages/join-e2e/tests/settings/fake-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,6 @@ export async function overrideFakeApi(rule: {
* Puts an object straight into the fake Stripe, as if it had been created
* there earlier, e.g. seedFakeStripe('customers', { id: 'cus_1', email: '...' }).
*/
export async function seedFakeStripe(type: 'products' | 'prices' | 'customers' | 'subscriptions', object: Record<string, unknown>): Promise<void> {
export async function seedFakeStripe(type: 'products' | 'prices' | 'customers' | 'subscriptions' | 'invoices', object: Record<string, unknown>): Promise<void> {
await control('POST', `/stripe/${type}`, object);
}
10 changes: 1 addition & 9 deletions packages/join-e2e/tests/settings/features-integrations.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Page } from '@playwright/test';
import { CONTINUE } from '../helpers';
import {
STANDARD_JOIN_PAGE,
continueToPayment,
expect,
expectDetailsAccepted,
expectDetailsRejected,
Expand Down Expand Up @@ -156,14 +156,6 @@ test.describe('Create Auth0 Account', () => {
});

test.describe('Payment providers', () => {
/** From the details step, through the plan step, to whatever comes next. */
async function continueToPayment(page: Page) {
await page.locator(CONTINUE).click();
await page.waitForSelector('[role="radiogroup"]');
await page.locator('label.radio-panel').first().click();
await page.locator(CONTINUE).click();
}

const logo = (page: Page, provider: string) => page.locator(`.progress-steps img[alt="${provider}"]`);

test('none is on by default: no provider logos', async ({ page }) => {
Expand Down
4 changes: 2 additions & 2 deletions packages/join-e2e/tests/settings/features.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { CONTINUE } from '../helpers';
import {
FREE_JOIN_PAGE,
continueToPlans,
expect,
expectDetailsAccepted,
expectDetailsRejected,
Expand Down Expand Up @@ -266,8 +267,7 @@ test.describe('Enable international phone numbers', () => {
test.describe('Hide price display for zero-price items', () => {
async function goToPlans(page: import('@playwright/test').Page) {
await openJoinForm(page, FREE_JOIN_PAGE);
await page.locator(CONTINUE).click();
await page.waitForSelector('[role="radiogroup"]');
await continueToPlans(page);
}

test('is off by default: a free plan shows its £0 price', async ({ page }) => {
Expand Down
Loading
Loading