diff --git a/.prettierignore b/.prettierignore index 87cc33e7d22..f1f16777ad9 100644 --- a/.prettierignore +++ b/.prettierignore @@ -21,6 +21,11 @@ packages/boxel-cli/plugin/skills/ # breaks its recorded SHA-256 and drifts it from its documented provenance. packages/experiments-realm/filedef-fixtures/samples/ +# Fonts, font stylesheets and an image that the matrix tests serve in place of +# the internet copies the Synapse email templates load. They are the bytes the +# browser received from those hosts; reformatting drifts them from that. +packages/matrix/support/email-assets/ + # Vendored third-party bundles and data in Pret UI. Each directory's README.md # records the upstream version and build; reformatting drifts the bytes from it. packages/pretui/color/index.js diff --git a/packages/matrix/helpers/email-assets.ts b/packages/matrix/helpers/email-assets.ts new file mode 100644 index 00000000000..58df010d03a --- /dev/null +++ b/packages/matrix/helpers/email-assets.ts @@ -0,0 +1,104 @@ +import { readFileSync } from 'fs'; +import { join } from 'path'; +import type { BrowserContext, Frame, Request } from '@playwright/test'; +import { mailHost } from './index.ts'; + +// The Synapse email and validation-page templates +// (support/synapse/templates/_base.html) load web fonts and the Boxel logo +// from the internet. Those stylesheets block rendering, so when one of them is +// slow the email shows as a blank pane in the mail client and the screenshot +// assertions fail. These are the bytes the browser received for each URL, +// served locally so the screenshots no longer depend on those hosts. +const assetsDir = join(import.meta.dirname, '..', 'support', 'email-assets'); + +const EXTERNAL_HOSTS = [ + 'fonts.googleapis.com', + 'fonts.gstatic.com', + 'fonts.cdnfonts.com', + 'd12nxmpmo97fii.cloudfront.net', +]; + +const ASSETS: Record = { + 'https://fonts.googleapis.com/css2?family=Poppins:wght@400': { + file: 'poppins-400.css', + contentType: 'text/css; charset=utf-8', + }, + 'https://fonts.googleapis.com/css2?family=Poppins:wght@700': { + file: 'poppins-700.css', + contentType: 'text/css; charset=utf-8', + }, + 'https://fonts.googleapis.com/css?family=Open%20Sans': { + file: 'open-sans.css', + contentType: 'text/css; charset=utf-8', + }, + 'https://fonts.cdnfonts.com/css/arial-2': { + file: 'arial-2.css', + contentType: 'text/css; charset=utf-8', + }, + 'https://fonts.gstatic.com/s/poppins/v24/pxiEyp8kv8JHgFVrJJfecg.woff2': { + file: 'pxiEyp8kv8JHgFVrJJfecg.woff2', + contentType: 'font/woff2', + }, + 'https://fonts.gstatic.com/s/poppins/v24/pxiByp8kv8JHgFVrLCz7Z1xlFQ.woff2': { + file: 'pxiByp8kv8JHgFVrLCz7Z1xlFQ.woff2', + contentType: 'font/woff2', + }, + 'https://d12nxmpmo97fii.cloudfront.net/boxel-icon.png': { + file: 'boxel-icon.png', + contentType: 'image/png', + }, +}; + +const SYNAPSE_PAGE = /^https?:\/\/[^/]+\/_(matrix|synapse)\//; + +// The route is on the whole browser context, so host pages that load from these +// hosts reach it too, such as a card theme's web font. Only requests from the +// mail client (and the email in its iframe) or a page Synapse serves come from +// the templates. +function isFromEmailTemplate(request: Request): boolean { + let frame: Frame | null; + try { + frame = request.frame(); + } catch { + // service worker requests have no frame + return false; + } + for (; frame; frame = frame.parentFrame()) { + let url = frame.url(); + if (url.startsWith(mailHost) || SYNAPSE_PAGE.test(url)) { + return true; + } + } + return false; +} + +export async function routeEmailAssets(context: BrowserContext) { + await context.route( + (url) => EXTERNAL_HOSTS.includes(url.hostname), + async (route) => { + let request = route.request(); + let url = request.url(); + let asset = ASSETS[url]; + if (!asset) { + if (!isFromEmailTemplate(request)) { + // Not the templates' request: leave it to the network as before. + await route.fallback(); + return; + } + // A template now asks for something not stored here. Answer quickly + // so nothing waits on the network, and say so in the test output. + console.warn( + `email template asset not stored locally, answering 404: ${url} (add it to helpers/email-assets.ts)`, + ); + await route.fulfill({ status: 404, body: '' }); + return; + } + await route.fulfill({ + status: 200, + contentType: asset.contentType, + headers: { 'access-control-allow-origin': '*' }, + body: readFileSync(join(assetsDir, asset.file)), + }); + }, + ); +} diff --git a/packages/matrix/helpers/index.ts b/packages/matrix/helpers/index.ts index 13b36537310..94a45b7af71 100644 --- a/packages/matrix/helpers/index.ts +++ b/packages/matrix/helpers/index.ts @@ -425,6 +425,30 @@ export async function getMonacoContent(page: Page): Promise { ); } +// Logged before a test looks at the email, so that if the email pane is +// still blank the output shows whether the email's document, stylesheets, +// images and fonts had loaded. +async function logEmailFrameState(emailPage: Page) { + try { + let frame = await ( + await emailPage.locator('.messageview iframe').elementHandle() + )?.contentFrame(); + let state = await frame?.evaluate(() => ({ + readyState: document.readyState, + fonts: document.fonts.status, + stylesheets: [ + ...document.querySelectorAll('link[rel="stylesheet"]'), + ].map((link) => `${link.href} ${link.sheet ? 'loaded' : 'pending'}`), + images: [...document.images].map( + (image) => `${image.src} ${image.complete ? 'complete' : 'pending'}`, + ), + })); + console.log(`email frame state: ${JSON.stringify(state ?? 'no frame')}`); + } catch (e) { + console.log(`email frame state unavailable: ${e}`); + } +} + export async function validateEmail( appPage: Page, email: string, @@ -467,6 +491,7 @@ export async function validateEmail( await expect( emailPage.locator('.messageview .messageviewheader'), ).toContainText(`To:${email}`); + await logEmailFrameState(emailPage); if (opts?.onEmailPage) { await opts.onEmailPage(emailPage); @@ -525,6 +550,7 @@ export async function validateEmailForResetPassword( await expect( emailPage.locator('.messageview .messageviewheader'), ).toContainText(`To:${email}`); + await logEmailFrameState(emailPage); if (opts?.onEmailPage) { await opts.onEmailPage(emailPage); diff --git a/packages/matrix/support/email-assets/Poppins-OFL.txt b/packages/matrix/support/email-assets/Poppins-OFL.txt new file mode 100644 index 00000000000..76df3b56567 --- /dev/null +++ b/packages/matrix/support/email-assets/Poppins-OFL.txt @@ -0,0 +1,93 @@ +Copyright 2020 The Poppins Project Authors (https://github.com/itfoundry/Poppins) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/packages/matrix/support/email-assets/arial-2.css b/packages/matrix/support/email-assets/arial-2.css new file mode 100644 index 00000000000..68ed020d03a --- /dev/null +++ b/packages/matrix/support/email-assets/arial-2.css @@ -0,0 +1,8 @@ +@font-face { + font-family: 'Arial'; + font-style: normal; + font-weight: 900; + src: local('Arial'), url('https://fonts.cdnfonts.com/s/59002/Lalithabai.woff') format('woff'); +} + + diff --git a/packages/matrix/support/email-assets/boxel-icon.png b/packages/matrix/support/email-assets/boxel-icon.png new file mode 100644 index 00000000000..d8b9ad05bb5 Binary files /dev/null and b/packages/matrix/support/email-assets/boxel-icon.png differ diff --git a/packages/matrix/support/email-assets/open-sans.css b/packages/matrix/support/email-assets/open-sans.css new file mode 100644 index 00000000000..55ea444ff20 --- /dev/null +++ b/packages/matrix/support/email-assets/open-sans.css @@ -0,0 +1,90 @@ +/* cyrillic-ext */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 400; + font-stretch: 100%; + src: url(https://fonts.gstatic.com/s/opensans/v44/memSYaGs126MiZpBA-UvWbX2vVnXBbObj2OVZyOOSr4dVJWUgsjZ0B4taVIGxA.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 400; + font-stretch: 100%; + src: url(https://fonts.gstatic.com/s/opensans/v44/memSYaGs126MiZpBA-UvWbX2vVnXBbObj2OVZyOOSr4dVJWUgsjZ0B4kaVIGxA.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 400; + font-stretch: 100%; + src: url(https://fonts.gstatic.com/s/opensans/v44/memSYaGs126MiZpBA-UvWbX2vVnXBbObj2OVZyOOSr4dVJWUgsjZ0B4saVIGxA.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 400; + font-stretch: 100%; + src: url(https://fonts.gstatic.com/s/opensans/v44/memSYaGs126MiZpBA-UvWbX2vVnXBbObj2OVZyOOSr4dVJWUgsjZ0B4jaVIGxA.woff2) format('woff2'); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* hebrew */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 400; + font-stretch: 100%; + src: url(https://fonts.gstatic.com/s/opensans/v44/memSYaGs126MiZpBA-UvWbX2vVnXBbObj2OVZyOOSr4dVJWUgsjZ0B4iaVIGxA.woff2) format('woff2'); + unicode-range: U+0307-0308, U+0590-05FF, U+200C-2010, U+20AA, U+25CC, U+FB1D-FB4F; +} +/* math */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 400; + font-stretch: 100%; + src: url(https://fonts.gstatic.com/s/opensans/v44/memSYaGs126MiZpBA-UvWbX2vVnXBbObj2OVZyOOSr4dVJWUgsjZ0B5caVIGxA.woff2) format('woff2'); + unicode-range: U+0302-0303, U+0305, U+0307-0308, U+0310, U+0312, U+0315, U+031A, U+0326-0327, U+032C, U+032F-0330, U+0332-0333, U+0338, U+033A, U+0346, U+034D, U+0391-03A1, U+03A3-03A9, U+03B1-03C9, U+03D1, U+03D5-03D6, U+03F0-03F1, U+03F4-03F5, U+2016-2017, U+2034-2038, U+203C, U+2040, U+2043, U+2047, U+2050, U+2057, U+205F, U+2070-2071, U+2074-209F, U+20D0-20DC, U+20E1, U+20E5-20EF, U+2100-2112, U+2114-2115, U+2117-2121, U+2123-214F, U+2190, U+2192, U+2194-21AE, U+21B0-21E5, U+21F1-21F2, U+21F4-2211, U+2213-2214, U+2216-22FF, U+2308-230B, U+2310, U+2319, U+231C-2321, U+2336-237A, U+237C, U+2395, U+239B-23B7, U+23D0, U+23DC-23E1, U+2474-2475, U+25AF, U+25B3, U+25B7, U+25BD, U+25C1, U+25CA, U+25CC, U+25FB, U+266D-266F, U+27C0-27FF, U+2900-2AFF, U+2B0E-2B11, U+2B30-2B4C, U+2BFE, U+3030, U+FF5B, U+FF5D, U+1D400-1D7FF, U+1EE00-1EEFF; +} +/* symbols */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 400; + font-stretch: 100%; + src: url(https://fonts.gstatic.com/s/opensans/v44/memSYaGs126MiZpBA-UvWbX2vVnXBbObj2OVZyOOSr4dVJWUgsjZ0B5OaVIGxA.woff2) format('woff2'); + unicode-range: U+0001-000C, U+000E-001F, U+007F-009F, U+20DD-20E0, U+20E2-20E4, U+2150-218F, U+2190, U+2192, U+2194-2199, U+21AF, U+21E6-21F0, U+21F3, U+2218-2219, U+2299, U+22C4-22C6, U+2300-243F, U+2440-244A, U+2460-24FF, U+25A0-27BF, U+2800-28FF, U+2921-2922, U+2981, U+29BF, U+29EB, U+2B00-2BFF, U+4DC0-4DFF, U+FFF9-FFFB, U+10140-1018E, U+10190-1019C, U+101A0, U+101D0-101FD, U+102E0-102FB, U+10E60-10E7E, U+1D2C0-1D2D3, U+1D2E0-1D37F, U+1F000-1F0FF, U+1F100-1F1AE, U+1F1E6-1F1FF, U+1F30D-1F30F, U+1F315, U+1F31C, U+1F31E, U+1F320-1F32C, U+1F336, U+1F378, U+1F37D, U+1F382, U+1F393-1F39F, U+1F3A7-1F3A8, U+1F3AC-1F3AF, U+1F3C2, U+1F3C4-1F3C6, U+1F3CA-1F3CE, U+1F3D4-1F3E0, U+1F3ED, U+1F3F1-1F3F3, U+1F3F5-1F3F7, U+1F408, U+1F415, U+1F41F, U+1F426, U+1F43F, U+1F441-1F442, U+1F444, U+1F446-1F449, U+1F44C-1F44E, U+1F453, U+1F46A, U+1F47D, U+1F4A3, U+1F4B0, U+1F4B3, U+1F4B9, U+1F4BB, U+1F4BF, U+1F4C8-1F4CB, U+1F4D6, U+1F4DA, U+1F4DF, U+1F4E3-1F4E6, U+1F4EA-1F4ED, U+1F4F7, U+1F4F9-1F4FB, U+1F4FD-1F4FE, U+1F503, U+1F507-1F50B, U+1F50D, U+1F512-1F513, U+1F53E-1F54A, U+1F54F-1F5FA, U+1F610, U+1F650-1F67F, U+1F687, U+1F68D, U+1F691, U+1F694, U+1F698, U+1F6AD, U+1F6B2, U+1F6B9-1F6BA, U+1F6BC, U+1F6C6-1F6CF, U+1F6D3-1F6D7, U+1F6E0-1F6EA, U+1F6F0-1F6F3, U+1F6F7-1F6FC, U+1F700-1F80B, U+1F810-1F847, U+1F850-1F859, U+1F860-1F887, U+1F890-1F8AD, U+1F8B0-1F8BB, U+1F8C0-1F8C1, U+1F8D0-1F8D8, U+1F900-1F90B, U+1F93B, U+1F946, U+1F984, U+1F996, U+1F9E9, U+1FA00-1FA6F, U+1FA70-1FA7C, U+1FA80-1FAC6, U+1FAC8, U+1FACC-1FADD, U+1FADF-1FAEB, U+1FAEF-1FAFA, U+1FB00-1FBFF; +} +/* vietnamese */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 400; + font-stretch: 100%; + src: url(https://fonts.gstatic.com/s/opensans/v44/memSYaGs126MiZpBA-UvWbX2vVnXBbObj2OVZyOOSr4dVJWUgsjZ0B4vaVIGxA.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 400; + font-stretch: 100%; + src: url(https://fonts.gstatic.com/s/opensans/v44/memSYaGs126MiZpBA-UvWbX2vVnXBbObj2OVZyOOSr4dVJWUgsjZ0B4uaVIGxA.woff2) format('woff2'); + unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 400; + font-stretch: 100%; + src: url(https://fonts.gstatic.com/s/opensans/v44/memSYaGs126MiZpBA-UvWbX2vVnXBbObj2OVZyOOSr4dVJWUgsjZ0B4gaVI.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} diff --git a/packages/matrix/support/email-assets/poppins-400.css b/packages/matrix/support/email-assets/poppins-400.css new file mode 100644 index 00000000000..a8bba6c13cb --- /dev/null +++ b/packages/matrix/support/email-assets/poppins-400.css @@ -0,0 +1,24 @@ +/* devanagari */ +@font-face { + font-family: 'Poppins'; + font-style: normal; + font-weight: 400; + src: url(https://fonts.gstatic.com/s/poppins/v24/pxiEyp8kv8JHgFVrJJbecmNE.woff2) format('woff2'); + unicode-range: U+0900-097F, U+1CD0-1CF4, U+1CF7-1CF9, U+200C-200D, U+20A8, U+20B9, U+20F0, U+25CC, U+A830-A839, U+A8E0-A8FF, U+11B00-11B0A; +} +/* latin-ext */ +@font-face { + font-family: 'Poppins'; + font-style: normal; + font-weight: 400; + src: url(https://fonts.gstatic.com/s/poppins/v24/pxiEyp8kv8JHgFVrJJnecmNE.woff2) format('woff2'); + unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Poppins'; + font-style: normal; + font-weight: 400; + src: url(https://fonts.gstatic.com/s/poppins/v24/pxiEyp8kv8JHgFVrJJfecg.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} diff --git a/packages/matrix/support/email-assets/poppins-700.css b/packages/matrix/support/email-assets/poppins-700.css new file mode 100644 index 00000000000..e9632e64cf9 --- /dev/null +++ b/packages/matrix/support/email-assets/poppins-700.css @@ -0,0 +1,24 @@ +/* devanagari */ +@font-face { + font-family: 'Poppins'; + font-style: normal; + font-weight: 700; + src: url(https://fonts.gstatic.com/s/poppins/v24/pxiByp8kv8JHgFVrLCz7Z11lFc-K.woff2) format('woff2'); + unicode-range: U+0900-097F, U+1CD0-1CF4, U+1CF7-1CF9, U+200C-200D, U+20A8, U+20B9, U+20F0, U+25CC, U+A830-A839, U+A8E0-A8FF, U+11B00-11B0A; +} +/* latin-ext */ +@font-face { + font-family: 'Poppins'; + font-style: normal; + font-weight: 700; + src: url(https://fonts.gstatic.com/s/poppins/v24/pxiByp8kv8JHgFVrLCz7Z1JlFc-K.woff2) format('woff2'); + unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Poppins'; + font-style: normal; + font-weight: 700; + src: url(https://fonts.gstatic.com/s/poppins/v24/pxiByp8kv8JHgFVrLCz7Z1xlFQ.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} diff --git a/packages/matrix/support/email-assets/pxiByp8kv8JHgFVrLCz7Z1xlFQ.woff2 b/packages/matrix/support/email-assets/pxiByp8kv8JHgFVrLCz7Z1xlFQ.woff2 new file mode 100644 index 00000000000..bf022fc77e7 Binary files /dev/null and b/packages/matrix/support/email-assets/pxiByp8kv8JHgFVrLCz7Z1xlFQ.woff2 differ diff --git a/packages/matrix/support/email-assets/pxiEyp8kv8JHgFVrJJfecg.woff2 b/packages/matrix/support/email-assets/pxiEyp8kv8JHgFVrJJfecg.woff2 new file mode 100644 index 00000000000..b69e0091c26 Binary files /dev/null and b/packages/matrix/support/email-assets/pxiEyp8kv8JHgFVrJJfecg.woff2 differ diff --git a/packages/matrix/tests/fixtures.ts b/packages/matrix/tests/fixtures.ts index 792c2daffce..ee8d9e45d39 100644 --- a/packages/matrix/tests/fixtures.ts +++ b/packages/matrix/tests/fixtures.ts @@ -1,7 +1,12 @@ import { test as base, expect } from '@playwright/test'; import { setRealmRedirects } from '../helpers/index.ts'; +import { routeEmailAssets } from '../helpers/email-assets.ts'; export const test = base.extend({ + context: async ({ context }, use) => { + await routeEmailAssets(context); + await use(context); + }, page: async ({ page }, use) => { await setRealmRedirects(page); await use(page);