From 03280ebc8d8ecf4b08890c27589cce0c0bcddf91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20C=C3=A9lio?= Date: Thu, 18 Nov 2021 15:22:56 -0300 Subject: [PATCH 01/21] refactor: moving image to a separated folder --- .../public}/images/pyramid-of-testing-front-end.png | Bin 1 file changed, 0 insertions(+), 0 deletions(-) rename {posts/src => webapp/public}/images/pyramid-of-testing-front-end.png (100%) diff --git a/posts/src/images/pyramid-of-testing-front-end.png b/webapp/public/images/pyramid-of-testing-front-end.png similarity index 100% rename from posts/src/images/pyramid-of-testing-front-end.png rename to webapp/public/images/pyramid-of-testing-front-end.png From 309bc533ec4ffa3e7cd64999a5d1648a8102d6e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20C=C3=A9lio?= Date: Thu, 18 Nov 2021 15:30:02 -0300 Subject: [PATCH 02/21] refactor:update english post to another folder --- posts/src/{posts => }/en/testing-in-front-end.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename posts/src/{posts => }/en/testing-in-front-end.md (98%) diff --git a/posts/src/posts/en/testing-in-front-end.md b/posts/src/en/testing-in-front-end.md similarity index 98% rename from posts/src/posts/en/testing-in-front-end.md rename to posts/src/en/testing-in-front-end.md index 0dcea4e..383bff8 100644 --- a/posts/src/posts/en/testing-in-front-end.md +++ b/posts/src/en/testing-in-front-end.md @@ -30,7 +30,7 @@ Another one is [The Testing Trophy](https://twitter.com/kentcdodds/status/960723 What I going to present here is based on Martin Fowler Pyramid of Testing with some little changes to represent **more general perspective of testing in front end**. Looks like this: -![Pyramid of Testing Front End Adapted](../../images/pyramid-of-testing-front-end.png "Pyramid of Testing Front End Adapted") +![Pyramid of Testing Front End Adapted](/images/pyramid-of-testing-front-end.png "Pyramid of Testing Front End Adapted") These boundaries in the pyramid is what I call **levels** in this article. Each level represent a different purpose of testing. These levels can have different **types** of tests. Define tests types can be fuzzy and difficult because sometimes we don't have a good separation in the code. From 311791b482374a36398bf1548effeeaff032ca50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20C=C3=A9lio?= Date: Thu, 18 Nov 2021 15:30:16 -0300 Subject: [PATCH 03/21] feat: add testing in front end ptbr file --- posts/src/ptBr/testing-in-front-end.md | 88 ++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 posts/src/ptBr/testing-in-front-end.md diff --git a/posts/src/ptBr/testing-in-front-end.md b/posts/src/ptBr/testing-in-front-end.md new file mode 100644 index 0000000..58e7bb5 --- /dev/null +++ b/posts/src/ptBr/testing-in-front-end.md @@ -0,0 +1,88 @@ +--- +title: Testing in Front End +description: Aprenda a fazer melhores testes em seu front end. +createdAt: '2021-11-03T02:11:11.781Z' +updatedAt: '2021-11-03T02:11:11.781Z' +tags: + - front-end + - testing +--- + +Ao longo da minha jornada como desenvolvedor, percebo que alguns colegas têm dificuldade em realizar testes no front end. Às vezes o problema é sobre não estar familiarizado, Ou sobre os detalhes de uma framework. Mas às vezes é **saber sobre o que você deve ser coberto**. Alguns livros (bons livros) até descrevem isso como difícil de fazer, dizendo que não é uma boa ideia. Mas estamos em 2021, e as ferramentas de teste evoluíram para fazer um bom teste de uma UI no front end. + +Neste artigo, abordo os tipos comuns de teste, uma visão geral desses tipos e exemplos de ferramentas que você pode usar para fazer com que funcionem. + +## Aviso + +Ao ler este artigo, espero que você conhecesse os fundamentos dos testes e tenha alguma experiência nisso. **Se você não sabe nada sobre testes, este artigo não é para você**. + +Dito isso, vamos lá! + +## Pirâmide de teste + +Você provavelmente conhece esta pirâmide específica de teste. Foi originalmente criada no [artigo de Martin Fowler sobre testes em Engenharia de Software](https://martinfowler.com/articles/practical-test-pyramid.html). + +! [A pirâmide de teste - Martin Fowler](https://martinfowler.com/articles/practical-test-pyramid/testPyramid.png) + +Outro é [The Testing Trophy](https://twitter.com/kentcdodds/status/960723172591992832?lang=es), de Kent C Dodds, e dá outra perspectiva sobre o mesmo assunto. + +! [Troféu de teste - Kent C Dodds](https://pbs.twimg.com/media/DVUoM94VQAAzuws?format=jpg&name=900x900) + +O que vou apresentar aqui é baseado na Pirâmide de Teste de Martin Fowler com algumas pequenas mudanças para representar **uma perspectiva mais geral de teste no front end**, e ela se parece com isso: + +! [Pirâmide de front-end de teste adaptada](/ images / pyramid-of-testing-front-end.png "Pirâmide de front-end de teste adaptada") + +Esses limites na pirâmide são o que chamo de **níveis** neste artigo. Cada nível representa um propósito diferente de teste. Esses níveis podem ter diferentes **tipos** de testes. Definir os tipos de teste pode ser confuso e difícil porque às vezes não temos uma boa separação no código. + +Lembre-se de que o que estou apresentando aqui é baseado em **problemas comuns** que queremos resolver no desenvolvimento de UI (especialmente aplicativos da web). Mas **você não precisa ter tudo** em sua base de código, você sempre precisa identificar quais são eles de que você precisa antes de colocar em seu projeto. + +Vamos começar com os **níveis e tipos mais comuns**. + +### Nível de componente + +Hoje em dia, é comum usar uma abordagem de componente. Começamos a criar componentes que têm pequenas partes de nosso layout e, em seguida, costuramos para criar uma página inteira. Usando isso como princípio, podemos ter alguns níveis de teste. +Neste nível, testamos o que vamos usar no código dos componentes. Idealmente, nossos componentes são desacoplados do resto do código. Portanto, podemos testá-lo independentemente, para trabalhar com qualquer entrada. + +#### Snapshots test + +Normalmente não usamos HTML bruto para criar nosso código. React, Vue e Angular vêm para resgatar. Portanto, o primeiro teste que você deseja ter em nossa base de código é o snapshot test. Com esse teste, podemos garantir que o componente feito no React, por exemplo, está renderizando a mesma saída em HTML que deveria estar no navegador. + +A estrutura de teste dessas bibliotecas de componentes tem uma maneira de renderizar o HTML real e, então, você pode salvá-lo usando uma ferramenta de snapshot. [Jest tem uma documentação](https://jestjs.io/docs/snapshot-testing) para fazer isso. + +#### Teste de interação + +Os aplicativos da Web são feitos por interações e nossos componentes têm métodos que podem ser chamados pela interação de um usuário. Se um usuário clicar em um botão e abrir uma lista suspensa, você deseja testar se essas interações estão funcionando conforme o esperado e abrir a lista suspensa corretamente. Normalmente, os frameworks de teste têm uma maneira de testar isso também, um exemplo de ferramenta incrível é a [testing-library](https://testing-library.com/docs/). + +#### Regressão visual + +A UI é feita por pixels. Você quer ter certeza de que o visual dos componentes que você escreve não muda quando você faz uma refatoração. Com o teste de regressão visual você pode cuidar disso fazendo uma captura de tela do componente dentro de uma tela e compará-lo com a versão anterior. Às vezes pode ser complicado, como com animações, com sistemas operacionais diferentes, navegadores diferentes, resoluções de tela diferentes, etc. Mas geralmente é uma boa ideia tê-lo em sua base de código em algum nível. + +Para fazer esse teste, você precisa colocar seu componente em um navegador real e fazer uma captura de tela dele. Portanto, você precisa de algo emulando o componente no navegador. Você pode fazer isso com [Cypress](https://www.cypress.io/), [Playwright](https://playwright.dev/), [Storybook](https://storybook.js.org/) com [Loki](https://loki.js.org/) ou [Chromatic](https://www.chromatic.com/). + +### Nível de aplicação + +#### Teste funcional + +Teste funcional clássico, você pode usar para testar funções, auxiliares, camada de dados e etc. + +#### Teste de integração + +Você pode usar o termo teste de integração para descrever esses testes construindo o aplicativo inteiro, servir e tentar executar alguns dos principais cenários felizes + +### End-to-End test + +Você pode ver isso como um teste de recurso testando O aplicativo pela perspectiva do usuário. Esse teste é frágil e pode ser difícil de fazer, mas é uma boa maneira de testar o aplicativo. Você pode fazer isso com as mesmas ferramentas do nível do aplicativo. + +## Conclusion + +Espero que o conhecimento de alguns tipos e níveis diferentes de teste possa ajudá-lo a tomar boas decisões sobre quais testes você precisa em sua base de código. Embora, **o que e como é com você e sua equipe. Só não se esqueça de testar, seu futuro eu agradecerá**. + +## References + +Algumas referências e estudos adicionais sobre teste e arquitetura de front end. Faça um bom uso: + +- [ARTICLE: Practical Test Pyramid by *Martin Fowler*](https://martinfowler.com/articles/practical-test-pyramid.html) +- [ARTICLE: Unit test by *Martin Fowler*](https://martinfowler.com/bliki/UnitTest.html) +- [ARTICLE: Gherkin Language by *Cucumber*](https://cucumber.io/docs/gherkin/) +- [ARTICLE: Atomic Design by *Brad Frost*](https://bradfrost.com/blog/post/atomic-web-design/) +- [BOOK: Clean Code by *Martin Robert C.*](https://www.amazon.com.br/dp/B001GSTOAM/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1) From 5e537e9c25edb809d8dba446fb89853d4d1fa4d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20C=C3=A9lio?= Date: Thu, 18 Nov 2021 15:30:46 -0300 Subject: [PATCH 04/21] refactor: update vale.ini src entrypoint --- posts/.vale.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/posts/.vale.ini b/posts/.vale.ini index 1039403..aa6ef24 100644 --- a/posts/.vale.ini +++ b/posts/.vale.ini @@ -2,6 +2,6 @@ StylesPath = .vale/StylesPath MinAlertLevel = warning # Only Markdown and .txt files; change to whatever you're using. -[*.{md,txt}] +[src/en/*.{md,txt}] # List of styles to load. BasedOnStyles = Openly \ No newline at end of file From 2200ef3b938fe411488fd0bc533e4ba844352fc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20C=C3=A9lio?= Date: Thu, 18 Nov 2021 15:30:55 -0300 Subject: [PATCH 05/21] chore: update spellcheck script --- posts/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/posts/package.json b/posts/package.json index 7358578..21e1c3b 100644 --- a/posts/package.json +++ b/posts/package.json @@ -8,7 +8,7 @@ "scripts": { "spellcheck": "npm run spellcheck:en", "spellcheck:en": "npm run spellcheck:en:fix -- --report", - "spellcheck:en:fix": "mdspell 'src/posts/en/**/*.md' --ignore-acronyms --en-us", + "spellcheck:en:fix": "mdspell 'src/en/**/*.md' --ignore-acronyms --en-us", "lint:markdown": "markdownlint './src/**/*.md'", "lint:markdown:fix": "npm run lint -- --fix", "lint:spell": "vale --glob='*.{md}' src", From 3c549871e16719f6806a3292d58afc99e455aa52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20C=C3=A9lio?= Date: Thu, 18 Nov 2021 15:42:09 -0300 Subject: [PATCH 06/21] chore: rename post folder names --- posts/src/{en => en-US}/testing-in-front-end.md | 0 posts/src/{ptBr => pt-BR}/testing-in-front-end.md | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename posts/src/{en => en-US}/testing-in-front-end.md (100%) rename posts/src/{ptBr => pt-BR}/testing-in-front-end.md (100%) diff --git a/posts/src/en/testing-in-front-end.md b/posts/src/en-US/testing-in-front-end.md similarity index 100% rename from posts/src/en/testing-in-front-end.md rename to posts/src/en-US/testing-in-front-end.md diff --git a/posts/src/ptBr/testing-in-front-end.md b/posts/src/pt-BR/testing-in-front-end.md similarity index 100% rename from posts/src/ptBr/testing-in-front-end.md rename to posts/src/pt-BR/testing-in-front-end.md From e2c7aefe993b510aeead751e094f4774eca1bca0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20C=C3=A9lio?= Date: Thu, 18 Nov 2021 15:42:34 -0300 Subject: [PATCH 07/21] refactor: article file system to use language as dependancy --- webapp/src/infra/ArticleFileSystemRepository.ts | 14 ++++++++++---- .../unit/infra/ArticleFileSystemRepository.spec.ts | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/webapp/src/infra/ArticleFileSystemRepository.ts b/webapp/src/infra/ArticleFileSystemRepository.ts index 9130866..91ba427 100644 --- a/webapp/src/infra/ArticleFileSystemRepository.ts +++ b/webapp/src/infra/ArticleFileSystemRepository.ts @@ -4,11 +4,17 @@ import { ArticleRepository } from "../data"; import { Article, ArticleMetadata } from "../domain"; import frontMatterParser from "gray-matter"; -const ARTICLE_FILE_PATH = path.resolve(process.cwd(), "../posts/src/posts/en"); +const ARTICLE_FILE_PATH = path.resolve(process.cwd(), "posts/src"); export class ArticleFileSystemRepository implements ArticleRepository { + constructor( + private language: string, + private articleFilePath = path.resolve( + ARTICLE_FILE_PATH, language + ) + ) {} async findArticleBySlug(slug: string): Promise
{ - const filePath = path.join(ARTICLE_FILE_PATH, `${slug}.md`); + const filePath = path.join(this.articleFilePath, `${slug}.md`); const file = fs.readFileSync(filePath); const { data: { title, createdAt, updatedAt, description }, @@ -37,11 +43,11 @@ export class ArticleFileSystemRepository implements ArticleRepository { return this.findArticleBySlug(slug).then( ({ content, ...articleMetadata }) => articleMetadata ); - }) + }); return Promise.all(articleMetadataPromises); } private getArticleFileNames(): string[] { - return fs.readdirSync(ARTICLE_FILE_PATH); + return fs.readdirSync(this.articleFilePath); } } diff --git a/webapp/tests/unit/infra/ArticleFileSystemRepository.spec.ts b/webapp/tests/unit/infra/ArticleFileSystemRepository.spec.ts index c81230f..2fd94dd 100644 --- a/webapp/tests/unit/infra/ArticleFileSystemRepository.spec.ts +++ b/webapp/tests/unit/infra/ArticleFileSystemRepository.spec.ts @@ -2,7 +2,7 @@ import { ArticleRepository } from "../../../src/data"; import { ArticleFileSystemRepository } from "../../../src/infra/ArticleFileSystemRepository"; describe("infra :: ArticleFileSystemRepository", () => { - const articleFileSystemRepository: ArticleRepository = new ArticleFileSystemRepository(); + const articleFileSystemRepository: ArticleRepository = new ArticleFileSystemRepository("en-US"); it("should find an article by slug with success", async () => { const article = await articleFileSystemRepository.findArticleBySlug('testing-in-front-end') expect(article.slug).toBe("testing-in-front-end"); From 7f98013abcc3e43e87c10835a30067b9f7f19a1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20C=C3=A9lio?= Date: Thu, 18 Nov 2021 15:42:55 -0300 Subject: [PATCH 08/21] refactor: create article repository factory to use language as dependancy --- webapp/src/factories/createArticleRepository.ts | 8 +++----- webapp/src/pages/articles/[slug].tsx | 8 ++++---- webapp/src/pages/index.tsx | 5 +++-- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/webapp/src/factories/createArticleRepository.ts b/webapp/src/factories/createArticleRepository.ts index c9351b6..e2694c6 100644 --- a/webapp/src/factories/createArticleRepository.ts +++ b/webapp/src/factories/createArticleRepository.ts @@ -1,8 +1,6 @@ import { ArticleRepository } from "../data"; import { ArticleFileSystemRepository } from "../infra"; -export function createArticleRepository(): ArticleRepository { - return new ArticleFileSystemRepository(); -} - -export const articleRepository = createArticleRepository(); \ No newline at end of file +export function createArticleRepository(language: string): ArticleRepository { + return new ArticleFileSystemRepository(language); +} \ No newline at end of file diff --git a/webapp/src/pages/articles/[slug].tsx b/webapp/src/pages/articles/[slug].tsx index 1443502..1e3f187 100644 --- a/webapp/src/pages/articles/[slug].tsx +++ b/webapp/src/pages/articles/[slug].tsx @@ -2,8 +2,7 @@ import { GetStaticProps, GetStaticPaths } from "next"; import { ArticlePage } from "../../components/templates/ArticlePage"; import { Markdown } from "../../components/atoms/Markdown"; import { formatDate } from "../../components/global/formatDate"; -import { ArticleRepository } from "../../data"; -import { ArticleFileSystemRepository } from "../../infra"; +import { createArticleRepository } from "../../factories"; export interface ArticleProps { content: string; @@ -25,11 +24,11 @@ export default function Article({ ); } -let articleRepository: ArticleRepository = new ArticleFileSystemRepository(); - export const getStaticProps: GetStaticProps = async ({ params, + locale }) => { + const articleRepository = createArticleRepository(locale); const slug = params?.slug as string; const article = await articleRepository.findArticleBySlug(slug); return { @@ -42,6 +41,7 @@ export const getStaticProps: GetStaticProps = async ({ }; export const getStaticPaths: GetStaticPaths = async () => { + const articleRepository = createArticleRepository("en"); const articleSlugs = await articleRepository.getAllArticleSlugs(); return { paths: articleSlugs.map((slug) => ({ params: { slug } })), diff --git a/webapp/src/pages/index.tsx b/webapp/src/pages/index.tsx index 7707d38..ccacaaf 100644 --- a/webapp/src/pages/index.tsx +++ b/webapp/src/pages/index.tsx @@ -1,13 +1,14 @@ import { GetStaticProps } from "next"; import { formatDate } from "../components/global/formatDate"; -import { articleRepository } from "../factories"; import { HomePage, HomePageProps } from "../components/templates/HomePage"; +import { createArticleRepository } from "../factories"; function Home(props: HomePageProps) { return ; } -export const getStaticProps: GetStaticProps = async () => { +export const getStaticProps: GetStaticProps = async ({locale}) => { + const articleRepository = createArticleRepository(locale); const articles = await articleRepository.getAllArticleMetadata(); return { props: { From 3d494d91f68d10ee0214e7f3a42697162d56cb3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20C=C3=A9lio?= Date: Thu, 18 Nov 2021 15:43:04 -0300 Subject: [PATCH 09/21] refactor: update locales next.config.js --- webapp/next.config.js | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 webapp/next.config.js diff --git a/webapp/next.config.js b/webapp/next.config.js new file mode 100644 index 0000000..bd47a23 --- /dev/null +++ b/webapp/next.config.js @@ -0,0 +1,6 @@ +module.exports = { + i18n: { + locales: ["en-US", "pt-BR"], + defaultLocale: "en-US", + }, +}; From 2596d68be219e0bae68cb838889229b8262987b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20C=C3=A9lio?= Date: Thu, 18 Nov 2021 15:54:07 -0300 Subject: [PATCH 10/21] feat: add set locale function and global locale variable --- webapp/src/components/global/formatDate.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/webapp/src/components/global/formatDate.ts b/webapp/src/components/global/formatDate.ts index a4cda6b..f8fc100 100644 --- a/webapp/src/components/global/formatDate.ts +++ b/webapp/src/components/global/formatDate.ts @@ -1,4 +1,8 @@ -const locale = "en-US"; +let locale = "en-US"; + +export function setLocale(loc: string) { + locale = loc; +} export function formatDate(date: Date) { return date.toLocaleDateString(locale, { From df0ab045a49873c2d53c1048da8e0a8f99f2f75a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20C=C3=A9lio?= Date: Thu, 18 Nov 2021 15:54:25 -0300 Subject: [PATCH 11/21] refactor: update article file path --- webapp/src/infra/ArticleFileSystemRepository.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/src/infra/ArticleFileSystemRepository.ts b/webapp/src/infra/ArticleFileSystemRepository.ts index 91ba427..8a165fc 100644 --- a/webapp/src/infra/ArticleFileSystemRepository.ts +++ b/webapp/src/infra/ArticleFileSystemRepository.ts @@ -4,7 +4,7 @@ import { ArticleRepository } from "../data"; import { Article, ArticleMetadata } from "../domain"; import frontMatterParser from "gray-matter"; -const ARTICLE_FILE_PATH = path.resolve(process.cwd(), "posts/src"); +const ARTICLE_FILE_PATH = path.resolve(process.cwd(), "../posts/src"); export class ArticleFileSystemRepository implements ArticleRepository { constructor( From 2553a619f2b7cd9ebc3474f8069cea04a765ea25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20C=C3=A9lio?= Date: Thu, 18 Nov 2021 15:54:44 -0300 Subject: [PATCH 12/21] refactor: update post images references --- posts/src/pt-BR/testing-in-front-end.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/posts/src/pt-BR/testing-in-front-end.md b/posts/src/pt-BR/testing-in-front-end.md index 58e7bb5..a52bcde 100644 --- a/posts/src/pt-BR/testing-in-front-end.md +++ b/posts/src/pt-BR/testing-in-front-end.md @@ -1,5 +1,5 @@ --- -title: Testing in Front End +title: Teste no front end description: Aprenda a fazer melhores testes em seu front end. createdAt: '2021-11-03T02:11:11.781Z' updatedAt: '2021-11-03T02:11:11.781Z' @@ -22,15 +22,15 @@ Dito isso, vamos lá! Você provavelmente conhece esta pirâmide específica de teste. Foi originalmente criada no [artigo de Martin Fowler sobre testes em Engenharia de Software](https://martinfowler.com/articles/practical-test-pyramid.html). -! [A pirâmide de teste - Martin Fowler](https://martinfowler.com/articles/practical-test-pyramid/testPyramid.png) +![A pirâmide de teste - Martin Fowler](https://martinfowler.com/articles/practical-test-pyramid/testPyramid.png) Outro é [The Testing Trophy](https://twitter.com/kentcdodds/status/960723172591992832?lang=es), de Kent C Dodds, e dá outra perspectiva sobre o mesmo assunto. -! [Troféu de teste - Kent C Dodds](https://pbs.twimg.com/media/DVUoM94VQAAzuws?format=jpg&name=900x900) +![Troféu de teste - Kent C Dodds](https://pbs.twimg.com/media/DVUoM94VQAAzuws?format=jpg&name=900x900) O que vou apresentar aqui é baseado na Pirâmide de Teste de Martin Fowler com algumas pequenas mudanças para representar **uma perspectiva mais geral de teste no front end**, e ela se parece com isso: -! [Pirâmide de front-end de teste adaptada](/ images / pyramid-of-testing-front-end.png "Pirâmide de front-end de teste adaptada") +![Pirâmide de front-end de teste adaptada](/images/pyramid-of-testing-front-end.png "Pirâmide de front-end de teste adaptada") Esses limites na pirâmide são o que chamo de **níveis** neste artigo. Cada nível representa um propósito diferente de teste. Esses níveis podem ter diferentes **tipos** de testes. Definir os tipos de teste pode ser confuso e difícil porque às vezes não temos uma boa separação no código. From 5bed15988b1e124c20dfae7222f07d90ace11bfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20C=C3=A9lio?= Date: Thu, 18 Nov 2021 15:55:16 -0300 Subject: [PATCH 13/21] refactor: add locale as props in static generation --- webapp/src/pages/articles/[slug].tsx | 14 ++++++++++---- webapp/src/pages/index.tsx | 6 ++++-- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/webapp/src/pages/articles/[slug].tsx b/webapp/src/pages/articles/[slug].tsx index 1e3f187..0e029f1 100644 --- a/webapp/src/pages/articles/[slug].tsx +++ b/webapp/src/pages/articles/[slug].tsx @@ -1,7 +1,7 @@ import { GetStaticProps, GetStaticPaths } from "next"; import { ArticlePage } from "../../components/templates/ArticlePage"; import { Markdown } from "../../components/atoms/Markdown"; -import { formatDate } from "../../components/global/formatDate"; +import { formatDate, setLocale } from "../../components/global/formatDate"; import { createArticleRepository } from "../../factories"; export interface ArticleProps { @@ -28,6 +28,8 @@ export const getStaticProps: GetStaticProps = async ({ params, locale }) => { + setLocale(locale); + const articleRepository = createArticleRepository(locale); const slug = params?.slug as string; const article = await articleRepository.findArticleBySlug(slug); @@ -40,11 +42,15 @@ export const getStaticProps: GetStaticProps = async ({ }; }; -export const getStaticPaths: GetStaticPaths = async () => { - const articleRepository = createArticleRepository("en"); +export const getStaticPaths: GetStaticPaths = async ({ locales }) => { + const articleRepository = createArticleRepository("en-US"); const articleSlugs = await articleRepository.getAllArticleSlugs(); + + const paths = articleSlugs.map((slug) => ({ params: { slug } })); + const pathsByLocale = locales.map((locale) => paths.map((path) => ({...path, locale}))); + return { - paths: articleSlugs.map((slug) => ({ params: { slug } })), + paths: pathsByLocale.flat(), fallback: false, }; }; diff --git a/webapp/src/pages/index.tsx b/webapp/src/pages/index.tsx index ccacaaf..802a85e 100644 --- a/webapp/src/pages/index.tsx +++ b/webapp/src/pages/index.tsx @@ -1,5 +1,5 @@ import { GetStaticProps } from "next"; -import { formatDate } from "../components/global/formatDate"; +import { formatDate, setLocale } from "../components/global/formatDate"; import { HomePage, HomePageProps } from "../components/templates/HomePage"; import { createArticleRepository } from "../factories"; @@ -7,7 +7,9 @@ function Home(props: HomePageProps) { return ; } -export const getStaticProps: GetStaticProps = async ({locale}) => { +export const getStaticProps: GetStaticProps = async ({ locale }) => { + setLocale(locale); + const articleRepository = createArticleRepository(locale); const articles = await articleRepository.getAllArticleMetadata(); return { From 01320bcf45b741ca70d60f470734db71d9a93a82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20C=C3=A9lio?= Date: Thu, 18 Nov 2021 16:17:13 -0300 Subject: [PATCH 14/21] feat: add global locale context --- webapp/src/components/global/index.ts | 2 ++ webapp/src/components/global/locale.ts | 11 +++++++++++ 2 files changed, 13 insertions(+) create mode 100644 webapp/src/components/global/index.ts create mode 100644 webapp/src/components/global/locale.ts diff --git a/webapp/src/components/global/index.ts b/webapp/src/components/global/index.ts new file mode 100644 index 0000000..c59ab01 --- /dev/null +++ b/webapp/src/components/global/index.ts @@ -0,0 +1,2 @@ +export * from './formatDate'; +export * from './locale'; diff --git a/webapp/src/components/global/locale.ts b/webapp/src/components/global/locale.ts new file mode 100644 index 0000000..2d5585c --- /dev/null +++ b/webapp/src/components/global/locale.ts @@ -0,0 +1,11 @@ +import React from "react"; + +export interface Locale { + locale: string; + changeLocale: (locale: string) => void +} + +// @ts-ignore +export const LocaleContext = React.createContext(); + +export const useLocale = () => React.useContext(LocaleContext); \ No newline at end of file From e666259780cdcb08e854cfa98da97d7a9fdc71e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20C=C3=A9lio?= Date: Thu, 18 Nov 2021 16:17:27 -0300 Subject: [PATCH 15/21] feat: add button to change locale in header --- .../components/organisms/Header/Header.component.tsx | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/webapp/src/components/organisms/Header/Header.component.tsx b/webapp/src/components/organisms/Header/Header.component.tsx index 8bb7ddf..c0d6c7f 100644 --- a/webapp/src/components/organisms/Header/Header.component.tsx +++ b/webapp/src/components/organisms/Header/Header.component.tsx @@ -1,8 +1,19 @@ import { ProfileCard } from '../ProfileCard' +import { useLocale } from '../../global' + export function Header(){ + const { changeLocale } = useLocale() return (
+
    +
  • + +
  • +
  • + +
  • +
); } \ No newline at end of file From 0a5f7a49af6fa032264a92d624962a5aea0a6b50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20C=C3=A9lio?= Date: Thu, 18 Nov 2021 16:17:42 -0300 Subject: [PATCH 16/21] refactor: add locale provider in _app --- webapp/src/pages/_app.tsx | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/webapp/src/pages/_app.tsx b/webapp/src/pages/_app.tsx index 3aa3886..b510fa7 100644 --- a/webapp/src/pages/_app.tsx +++ b/webapp/src/pages/_app.tsx @@ -1,6 +1,20 @@ import "normalize.css"; import "../components/global/styles/global.css"; +import { LocaleContext } from "../components/global"; +import { useRouter } from "next/router"; +import type { AppProps } from "next/app"; -export default function MyApp({ Component, pageProps }) { - return ; +export default function MyApp({ Component, pageProps }: AppProps) { + const router = useRouter(); + const { pathname, asPath, query } = router; + + const changeLocale = (nextLocale) => { + router.push({ pathname, query }, asPath, { locale: nextLocale }); + }; + + return ( + + + + ); } From a9ae3084e951f65da302b5f4240a54b0a0a2fe8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20C=C3=A9lio?= Date: Thu, 18 Nov 2021 16:31:53 -0300 Subject: [PATCH 17/21] docs: update documentation --- README.md | 10 +--------- posts/README.md | 4 ---- webapp/README.md | 2 +- 3 files changed, 2 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 5a717bd..9e6068a 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,6 @@ # Blog -The code of my personal blog. **Is a working in progress.** - -## Roadmap - -1. [x] Configure the basics to create a article -2. [x] Create a first good article -3. [ ] Create the initial architecture -4. [ ] Create the minimum of the code to make it work -5. [ ] Deploy it +The code of my personal blog. ## Installation diff --git a/posts/README.md b/posts/README.md index 347d0ee..42305d5 100644 --- a/posts/README.md +++ b/posts/README.md @@ -4,10 +4,6 @@ This repository contains all the posts for the blog. # Folder structure -`images` -The images of the posts. - -`posts` All posts are in this folder and are organized by language tag. # Post files diff --git a/webapp/README.md b/webapp/README.md index 6bc38d9..649e724 100644 --- a/webapp/README.md +++ b/webapp/README.md @@ -1,3 +1,3 @@ # `@blog/webapp` -This repository contains all the code of the webapp of the blog \ No newline at end of file +This repository contains all the code of the webapp of the blog. \ No newline at end of file From 7495347ff74acd8a5c0b5819b0f6e042a3701114 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20C=C3=A9lio?= Date: Thu, 18 Nov 2021 17:44:30 -0300 Subject: [PATCH 18/21] feat: add language select component --- .../LanguageSelect.component.tsx | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 webapp/src/components/atoms/LanguageSelect/LanguageSelect.component.tsx diff --git a/webapp/src/components/atoms/LanguageSelect/LanguageSelect.component.tsx b/webapp/src/components/atoms/LanguageSelect/LanguageSelect.component.tsx new file mode 100644 index 0000000..388391d --- /dev/null +++ b/webapp/src/components/atoms/LanguageSelect/LanguageSelect.component.tsx @@ -0,0 +1,18 @@ +import { useLocale } from "../../global"; + +export function LanguageSelect() { + const { changeLocale, locale } = useLocale(); + return ( +
+ + +
+ ); +} From 28e1006539fcae57f5a688c3920681ec214fd32e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20C=C3=A9lio?= Date: Thu, 18 Nov 2021 17:44:41 -0300 Subject: [PATCH 19/21] refactor: add style for label and select --- webapp/src/components/global/styles/global.css | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/webapp/src/components/global/styles/global.css b/webapp/src/components/global/styles/global.css index c93e78e..6264947 100644 --- a/webapp/src/components/global/styles/global.css +++ b/webapp/src/components/global/styles/global.css @@ -88,6 +88,10 @@ h5 { header { text-align: center; padding: 4rem 0 1rem 0; + display: flex; + align-items: center; + align-content: center; + justify-content: space-between; } header a { @@ -108,4 +112,12 @@ article img { display: block; width: auto; max-width: 400px +} + +label, select { + font-size: 0.8rem; +} + +label { + margin-right: 0.5em; } \ No newline at end of file From c6e3b6ef254deba44f55efcf3e649b655d8b5e7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20C=C3=A9lio?= Date: Thu, 18 Nov 2021 17:44:55 -0300 Subject: [PATCH 20/21] refactor: add locale to locale context provider --- webapp/src/pages/_app.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/webapp/src/pages/_app.tsx b/webapp/src/pages/_app.tsx index b510fa7..4673cc2 100644 --- a/webapp/src/pages/_app.tsx +++ b/webapp/src/pages/_app.tsx @@ -6,14 +6,14 @@ import type { AppProps } from "next/app"; export default function MyApp({ Component, pageProps }: AppProps) { const router = useRouter(); - const { pathname, asPath, query } = router; + const { pathname, asPath, query, locale } = router; const changeLocale = (nextLocale) => { router.push({ pathname, query }, asPath, { locale: nextLocale }); }; return ( - + ); From 76847b755a496431ab1c1a7a944656d304e705a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20C=C3=A9lio?= Date: Thu, 18 Nov 2021 17:45:07 -0300 Subject: [PATCH 21/21] refactor: add language select component to header --- .../components/organisms/Header/Header.component.tsx | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/webapp/src/components/organisms/Header/Header.component.tsx b/webapp/src/components/organisms/Header/Header.component.tsx index c0d6c7f..ec20032 100644 --- a/webapp/src/components/organisms/Header/Header.component.tsx +++ b/webapp/src/components/organisms/Header/Header.component.tsx @@ -1,19 +1,11 @@ import { ProfileCard } from '../ProfileCard' -import { useLocale } from '../../global' +import { LanguageSelect } from '../../atoms/LanguageSelect/LanguageSelect.component'; export function Header(){ - const { changeLocale } = useLocale() return (
-
    -
  • - -
  • -
  • - -
  • -
+
); } \ No newline at end of file