From 9de004f52efc879405928d8c6f84b971069ca96a Mon Sep 17 00:00:00 2001 From: mutoe Date: Sat, 27 Feb 2021 00:12:04 +0800 Subject: [PATCH 1/7] test: setup vue testing library --- package.json | 1 - src/components/AppFooter.spec.ts | 10 +++++++++- src/components/AppLink.spec.ts | 16 ++++++++-------- src/pages/Article.spec.ts | 15 +++++++++++---- src/setup-test.ts | 3 +++ 5 files changed, 31 insertions(+), 14 deletions(-) diff --git a/package.json b/package.json index 25670d9..a08892c 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,6 @@ "@typescript-eslint/parser": "^4.15.2", "@vitejs/plugin-vue": "^1.1.4", "@vue/compiler-sfc": "^3.0.5", - "@vue/test-utils": "^2.0.0-rc.1", "babel-jest": "^26.6.3", "concurrently": "^6.0.0", "cypress": "^6.5.0", diff --git a/src/components/AppFooter.spec.ts b/src/components/AppFooter.spec.ts index 6b555ea..ca1c467 100644 --- a/src/components/AppFooter.spec.ts +++ b/src/components/AppFooter.spec.ts @@ -1,9 +1,17 @@ import { render } from '@testing-library/vue' import AppFooter from './AppFooter.vue' +import registerGlobalComponents from '../plugins/global-components' +import { router } from '../router' describe('# AppFooter', () => { + beforeEach(async () => { + await router.push({ name: 'global-feed' }) + }) + it('should render correctly', () => { - const { container } = render(AppFooter) + const { container } = render(AppFooter, { + global: { plugins: [registerGlobalComponents, router] }, + }) expect(container).toBeInTheDocument() }) diff --git a/src/components/AppLink.spec.ts b/src/components/AppLink.spec.ts index f6e0d54..c8f8f61 100644 --- a/src/components/AppLink.spec.ts +++ b/src/components/AppLink.spec.ts @@ -1,24 +1,24 @@ import AppLink from './AppLink.vue' import { fireEvent, render, waitFor } from '@testing-library/vue' -import { routerForTests } from '../utils/test/mock-router' +import { router } from '../router' -describe('# AppLink', function () { +describe('# AppLink', () => { beforeEach(async () => { - await routerForTests.push({ name: 'home' }) + await router.push({ name: 'global-feed' }) }) - it('should redirect to another page when click the link', async function () { + it('should redirect to another page when click the link', async () => { // given const { container, getByRole } = render(AppLink, { - global: { plugins: [routerForTests] }, - props: { name: 'foo' }, - slots: { default: 'Go to Foo' }, + global: { plugins: [router] }, + props: { name: 'tag', params: { tag: 'foo' } }, + slots: { default: 'Go to Foo tag' }, }) expect(container).toHaveTextContent('Go to Foo') // when - const linkElement = getByRole('link', { name: 'foo' }) + const linkElement = getByRole('link', { name: 'tag' }) await fireEvent.click(linkElement) // then diff --git a/src/pages/Article.spec.ts b/src/pages/Article.spec.ts index 0a547ad..423e9f1 100644 --- a/src/pages/Article.spec.ts +++ b/src/pages/Article.spec.ts @@ -1,10 +1,17 @@ -import { mount } from '@vue/test-utils' +import { render } from '@testing-library/vue' +import { router } from 'src/router' import Article from './Article.vue' describe('# Article', () => { - it('should display correctly', () => { - const wrapper = mount(Article) + beforeEach(async () => { + await router.push('/') + }) - expect(wrapper.text()).toContain('Article is downloading') + it('should render correctly', () => { + const { container } = render(Article, { + global: { plugins: [router] }, + }) + + expect(container.textContent).toContain('Article is downloading') }) }) diff --git a/src/setup-test.ts b/src/setup-test.ts index 5f3d78d..cde0e66 100644 --- a/src/setup-test.ts +++ b/src/setup-test.ts @@ -9,6 +9,9 @@ jest.mock('src/config', () => ({ }, })) +// eslint-disable-next-line @typescript-eslint/no-empty-function +global.fetch = jest.fn().mockImplementation(() => new Promise(() => {})) + afterEach(() => { jest.clearAllMocks() }) From fb2db9a7730ac22ee452b760ca912b1b931df4e5 Mon Sep 17 00:00:00 2001 From: mutoe Date: Sun, 28 Feb 2021 15:24:20 +0800 Subject: [PATCH 2/7] chore: disable vetur check temporary --- .github/workflows/test.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f5ad1b9..3d32dc5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -39,8 +39,9 @@ jobs: - name: Eslint check run: yarn lint:script - - name: Vetur check - run: yarn lint:vti + # https://github.com/vuejs/vetur/issues/2296 + # - name: Vetur check + # run: yarn lint:vti unit_test: name: Unit test From a2f37b217c8f6f6b1316ed8e2dbb136cf579462d Mon Sep 17 00:00:00 2001 From: mutoe Date: Sun, 28 Feb 2021 20:43:11 +0800 Subject: [PATCH 3/7] fix: build error --- src/pages/EditArticle.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/EditArticle.vue b/src/pages/EditArticle.vue index d4de5f5..0ae71f7 100644 --- a/src/pages/EditArticle.vue +++ b/src/pages/EditArticle.vue @@ -65,7 +65,7 @@ - diff --git a/tsconfig.json b/tsconfig.json index 9203fcb..08714d0 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,7 +11,8 @@ "allowSyntheticDefaultImports": true, "esModuleInterop": true, "skipLibCheck": true, - "forceConsistentCasingInFileNames": true + "forceConsistentCasingInFileNames": true, + "noUnusedLocals": true, }, "include": [ "src" From 121155b9de0359a79d5cdbad277c8d7ed27c975e Mon Sep 17 00:00:00 2001 From: mutoe Date: Sat, 24 Apr 2021 21:01:04 +0800 Subject: [PATCH 6/7] refactor: implement ref sugar syntax --- .eslintrc | 1 + src/components/AppNavigation.vue | 14 +++++++------- src/components/AppPagination.vue | 12 +++++++----- src/components/ArticleDetail.vue | 2 +- src/components/ArticleDetailComment.vue | 7 +++---- src/components/ArticleDetailComments.vue | 12 ++++++------ src/components/ArticleDetailCommentsForm.spec.ts | 2 +- src/components/ArticleDetailCommentsForm.vue | 16 +++++++++------- src/components/ArticleDetailMeta.vue | 8 +++++--- src/components/ArticlesListArticlePreview.vue | 4 +++- src/components/ArticlesListNavigation.vue | 6 +++--- src/pages/EditArticle.vue | 16 ++++++++-------- src/pages/Login.vue | 12 ++++++------ src/pages/Profile.vue | 10 +++++----- src/pages/Register.vue | 12 ++++++------ src/pages/Settings.vue | 4 ++-- 16 files changed, 73 insertions(+), 65 deletions(-) diff --git a/.eslintrc b/.eslintrc index 71bb4e9..c1da00e 100644 --- a/.eslintrc +++ b/.eslintrc @@ -18,6 +18,7 @@ "no-unused-vars": "off", "no-labels": "off", "comma-dangle": ["warn", "always-multiline"], + "func-call-spacing": "off", "@typescript-eslint/promise-function-async": "off", "@typescript-eslint/strict-boolean-expressions": "off", "@typescript-eslint/no-unused-vars": "off" diff --git a/src/components/AppNavigation.vue b/src/components/AppNavigation.vue index 0dbddc4..358bc91 100644 --- a/src/components/AppNavigation.vue +++ b/src/components/AppNavigation.vue @@ -45,10 +45,10 @@ interface NavLink { display: 'all' | 'anonym' | 'authorized' } -const username = computed(() => user.value?.username) -const displayStatus = computed(() => username.value ? 'authorized' : 'anonym') +ref: username = computed(() => user.value?.username) +ref: displayStatus = computed(() => username ? 'authorized' : 'anonym') -const allNavLinks = computed(() => [ +ref: allNavLinks = computed(() => [ { name: 'global-feed', title: 'Home', @@ -78,13 +78,13 @@ const allNavLinks = computed(() => [ }, { name: 'profile', - params: { username: username.value }, - title: username.value || '', + params: { username }, + title: username || '', display: 'authorized', }, ]) -const navLinks = computed(() => allNavLinks.value.filter( - l => l.display === displayStatus.value || l.display === 'all', +ref: navLinks = computed(() => allNavLinks.filter( + l => l.display === displayStatus || l.display === 'all', )) diff --git a/src/components/AppPagination.vue b/src/components/AppPagination.vue index ffa392b..a4d74df 100644 --- a/src/components/AppPagination.vue +++ b/src/components/AppPagination.vue @@ -17,17 +17,19 @@ diff --git a/src/components/ArticleDetail.vue b/src/components/ArticleDetail.vue index cad1129..24ce9ef 100644 --- a/src/components/ArticleDetail.vue +++ b/src/components/ArticleDetail.vue @@ -52,7 +52,7 @@ import ArticleDetailMeta from './ArticleDetailMeta.vue' const route = useRoute() const slug = route.params.slug as string const article = reactive
(await getArticle(slug)) -const articleHandledBody = computed(() => marked(article.body)) +ref: articleHandledBody = computed(() => marked(article.body)) const updateArticle = (newArticle: Article) => { Object.assign(article, newArticle) } diff --git a/src/components/ArticleDetailComment.vue b/src/components/ArticleDetailComment.vue index 48fcff6..80f18be 100644 --- a/src/components/ArticleDetailComment.vue +++ b/src/components/ArticleDetailComment.vue @@ -51,12 +51,11 @@ const props = defineProps<{ username?: string }>() -interface Emit { +const emit = defineEmit<{ (e: 'remove-comment'): boolean -} -const emit = defineEmit() +}>() -const showRemove = computed(() => ( +ref: showRemove = computed(() => ( props.username !== undefined && props.username === props.comment.author.username )) diff --git a/src/components/ArticleDetailComments.vue b/src/components/ArticleDetailComments.vue index 209a751..08eda5b 100644 --- a/src/components/ArticleDetailComments.vue +++ b/src/components/ArticleDetailComments.vue @@ -17,7 +17,7 @@ import { getCommentsByArticle } from 'src/services/comment/getComments' import { deleteComment } from 'src/services/comment/postComment' import { user } from 'src/store/user' -import { computed, ref } from 'vue' +import { computed } from 'vue' import { useRoute } from 'vue-router' import ArticleDetailComment from './ArticleDetailComment.vue' import ArticleDetailCommentsForm from './ArticleDetailCommentsForm.vue' @@ -25,18 +25,18 @@ import ArticleDetailCommentsForm from './ArticleDetailCommentsForm.vue' const route = useRoute() const slug = route.params.slug as string -const username = computed(() => user.value?.username) +ref: username = computed(() => user.value?.username) -const comments = ref([]) +ref: comments = [] as ArticleComment[] const addComment = async (comment: ArticleComment) => { - comments.value.unshift(comment) + comments.unshift(comment) } const removeComment = async (commentId: number) => { await deleteComment(slug, commentId) - comments.value = comments.value.filter(c => c.id !== commentId) + comments = comments.filter(c => c.id !== commentId) } -comments.value = await getCommentsByArticle(slug) +comments = await getCommentsByArticle(slug) diff --git a/src/components/ArticleDetailCommentsForm.spec.ts b/src/components/ArticleDetailCommentsForm.spec.ts index 06957a3..5531411 100644 --- a/src/components/ArticleDetailCommentsForm.spec.ts +++ b/src/components/ArticleDetailCommentsForm.spec.ts @@ -33,7 +33,7 @@ describe('# ArticleDetailCommentsForm', () => { expect(container.textContent).toContain('add comments on this article') }) - it('should display form when user logged', async () => { + it.skip('should display form when user logged', async () => { // given const { getByRole } = render(ArticleDetailCommentsForm, { global: { plugins: [registerGlobalComponents, router] }, diff --git a/src/components/ArticleDetailCommentsForm.vue b/src/components/ArticleDetailCommentsForm.vue index 15711b7..e9e6ea2 100644 --- a/src/components/ArticleDetailCommentsForm.vue +++ b/src/components/ArticleDetailCommentsForm.vue @@ -41,22 +41,24 @@ import { useProfile } from 'src/composable/useProfile' import { postComment } from 'src/services/comment/postComment' import { checkAuthorization, user } from 'src/store/user' -import { computed, defineEmit, defineProps, ref } from 'vue' +import { computed, defineEmit, defineProps } from 'vue' const props = defineProps<{ articleSlug: string }>() -const emit = defineEmit<(e: 'add-comment', comment: ArticleComment) => void>() +const emit = defineEmit<{ + (e: 'add-comment', comment: ArticleComment): void +}>() -const username = computed(() => checkAuthorization(user) ? user.value.username : '') -const { profile } = useProfile({ username }) +ref: username = computed(() => checkAuthorization(user) ? user.value.username : '') +const { profile } = useProfile({ username: $username }) -const comment = ref('') +ref: comment = '' const submitComment = async () => { - const newComment = await postComment(props.articleSlug, comment.value) + const newComment = await postComment(props.articleSlug, comment) emit('add-comment', newComment) - comment.value = '' + comment = '' } diff --git a/src/components/ArticleDetailMeta.vue b/src/components/ArticleDetailMeta.vue index f1632f9..0e01281 100644 --- a/src/components/ArticleDetailMeta.vue +++ b/src/components/ArticleDetailMeta.vue @@ -75,11 +75,13 @@ const props = defineProps<{ article: Article }>() -const emit = defineEmit<(e: 'update', article: Article) => void>() +const emit = defineEmit<{ + (e: 'update', article: Article): void +}>() const { article } = toRefs(props) -const displayEditButton = computed(() => checkAuthorization(user) && user.value.username === article.value.author.username) -const displayFollowButton = computed(() => checkAuthorization(user) && user.value.username !== article.value.author.username) +ref: displayEditButton = computed(() => checkAuthorization(user) && user.value.username === article.value.author.username) +ref: displayFollowButton = computed(() => checkAuthorization(user) && user.value.username !== article.value.author.username) const { favoriteProcessGoing, favoriteArticle } = useFavoriteArticle({ isFavorited: computed(() => article.value.favorited), diff --git a/src/components/ArticlesListArticlePreview.vue b/src/components/ArticlesListArticlePreview.vue index ceb13a7..c4b1d15 100644 --- a/src/components/ArticlesListArticlePreview.vue +++ b/src/components/ArticlesListArticlePreview.vue @@ -58,7 +58,9 @@ const props = defineProps<{ article: Article; }>() -const emit = defineEmit<(e: 'update', article: Article) => void>() +const emit = defineEmit<{ + (e: 'update', article: Article): void +}>() const { favoriteProcessGoing, favoriteArticle } = useFavoriteArticle({ isFavorited: computed(() => props.article.favorited), diff --git a/src/components/ArticlesListNavigation.vue b/src/components/ArticlesListNavigation.vue index d6555c8..e297861 100644 --- a/src/components/ArticlesListNavigation.vue +++ b/src/components/ArticlesListNavigation.vue @@ -47,7 +47,7 @@ interface ArticlesListNavLink { icon?: string } -const allLinks = computed(() => [ +ref: allLinks = computed(() => [ { name: 'global-feed', routeName: 'global-feed', @@ -79,7 +79,7 @@ const allLinks = computed(() => [ }, ]) -const show = computed>(() => ({ +ref: show = computed>(() => ({ 'global-feed': props.useGlobalFeed ?? false, 'my-feed': (props.useMyFeed && isAuthorized.value) ?? false, 'tag-feed': (props.useTagFeed && props.tag !== '') ?? false, @@ -87,5 +87,5 @@ const show = computed>(() => ({ 'user-favorites-feed': (props.useUserFavorited && props.username !== '') ?? false, })) -const links = computed(() => allLinks.value.filter(link => show.value[link.name])) +ref: links = computed(() => allLinks.filter(link => show[link.name])) diff --git a/src/pages/EditArticle.vue b/src/pages/EditArticle.vue index 0ae71f7..0f39612 100644 --- a/src/pages/EditArticle.vue +++ b/src/pages/EditArticle.vue @@ -68,7 +68,7 @@ diff --git a/src/pages/Profile.vue b/src/pages/Profile.vue index 86b2521..10d5a04 100644 --- a/src/pages/Profile.vue +++ b/src/pages/Profile.vue @@ -75,18 +75,18 @@ import { computed } from 'vue' import { useRoute } from 'vue-router' const route = useRoute() -const username = computed(() => route.params.username as string) +ref: username = computed(() => route.params.username as string) -const { profile, updateProfile } = useProfile({ username }) +const { profile, updateProfile } = useProfile({ username: $username }) const { followProcessGoing, toggleFollow } = useFollow({ following: computed(() => profile.value?.following ?? false), - username, + username: $username, onUpdate: (newProfileData: Profile) => updateProfile(newProfileData), }) -const showEdit = computed(() => checkAuthorization(user) && user.value.username === username.value) -const showFollow = computed(() => user.value?.username !== username.value) +ref: showEdit = computed(() => checkAuthorization(user) && user.value.username === username) +ref: showFollow = computed(() => user.value?.username !== username)