GithubHelp home page GithubHelp logo

next-router-mock's People

Contributors

bassochette avatar boredland avatar github-actions[bot] avatar harry-gocity avatar jackhkmatthews avatar jantimon avatar jmisasa avatar kamranayub avatar leedoopal avatar michaeltroya avatar scottrippey avatar soartec-lab avatar tom-streller-tutti avatar wickstopher avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

next-router-mock's Issues

mocked next/link behavior seems inconsistenst with next/link from next.js when the `as` prop is used

In our codebase we use the logic of dynamic paths and query parameters to create a more complex abstraction on top of the basic next.js routing logic. In essence, we have a couple of specific pages between we navigate using a next/link like in the example below:

<NextLink
    as={isStatic ? as : href} // isStatic resolves to false, so as=href
    prefetch={false}
    href={
        isStatic
            ? href
            : {
                  pathname: FriendlyPagesDestinations[type],
                  query: { [SLUG_TYPE_QUERY_PARAMETER_NAME]: FriendlyPagesTypes[type], ...queryParams },
              }
    }
    {...props}
>
    {children}
</NextLink>

If I navigate using the following link:

<ExtendedNextLink type="category" href="/test-category">
    link text
</ExtendedNextLink>,

the actual implementation of next/link shows me the following properties:

{
    asPath: "/test-category".
    pathname: "/categories/[categorySlug]", // this is caused by the dynamic pathname shown above
    query: { 
        slugType: "front_product_list" // also caused by the dynamic query above) 
    },
}

but the mocked one gets overwritten because of the as prop and by this logic in the mock (specifically in MemoryRouter):

const newRoute = parseUrlToCompleteUrl(url, this.pathname);
let asPath;
let asRoute;
if (as === undefined || as === null) {
    asRoute = undefined;
    asPath = getRouteAsPath(newRoute.pathname, newRoute.query, newRoute.hash);
}
else {
    asRoute = parseUrlToCompleteUrl(as, this.pathname);
    asPath = getRouteAsPath(asRoute.pathname, asRoute.query, asRoute.hash);
}

My question is, am I misunderstanding something? According to my understanding, if I navigate using a next/link where I paste arbitrary URL and query, the as prop should not overwrite it, as it should only modify the asPath property of the router. Is this a bug, or a feature?

Feature request: support NextJS rewrites

I might have programmed my self a bit into a corner here, but I have an app where I have the following rewrites:

async rewrites() {
    return [
        {
            source: '/',
            destination: '/null',
        },
        {
            source: '/some-route/:someId',
            destination: '/:someId',
        },
    ]
}

I do this in order to have a single page, called [someId].tsx to handle both root (e.g. no ID passed), and /some-route/some-value. This is of course a bit weird, but that's not important here. ๐Ÿ˜„ But to handle both rewrites pointing to the same page, I expect, according to the rewrites, the path parameter to be an actual string of type 'null' or an actual ID, and handle this is the code accordingly.

So naturally when testing this using jest and next-router-mock, when the application code redirects to / it would normally hit the rewrite, but in the test it doesn't. So the [someId].tsx page is rendered with an "illegal" state (illegal according to my own rewrite rules).

I could implement support for this test-only case in the application code, but I'm trying to avoid that. I also looked at using mockRouter.events.on('routeChangeStart', (evts) => {...}) as a way to handle my own rewrites, but it seems that was a dead end.

I know this is a bit of a weird case, but if anyone has any smart suggestions I'd be grateful. ๐Ÿ˜„ It would of course be cool if the dynamic routing could be configured to handle these kind of rewrites as well, but I'm not sure how that would work.

Usage with storybook

Hi, you mention this library can be used with storybook but I don't see any documentation for it, is it using MemoryRouter export and put it in component tree?

Support Next 13 'next/navigation' router

Module not found: Error: Can't resolve 'next/dist/next-server/lib/router-context'

Must be nice to have an implementation to mock useRouter of next/navigation

Issues with Jest.mock: "cannot read properties of null (reading 'pathname')"

Since NextJS doesn't have native active links, I am using the router to detect the current pathname and make sure it matches up to the Next Link href.

Component:

const router = useRouter();
const isActive = router.pathname === href;

In the test, I am mocking the router and setting the current url, but pathname is still undefined when I run the test, causing it to fail. "TypeError: Cannot read properties of null (reading 'pathname')"

Test:

import React from 'react';
import { render, screen } from '@testing-library/react';
import { faSearch } from '@fortawesome/pro-light-svg-icons';
import mockRouter from 'next-router-mock';
import { NavLink } from './NavLink';

jest.mock('next/dist/client/router', () => require('next-router-mock'));

describe('NavLink', () => {
  beforeEach(() => {
    mockRouter.setCurrentUrl('/initial');
  });

  it('should render the link label', () => {
    render(
      <NavLink
        icon={faSearch}
        label="Jobs"
        isActive={false}
        collapsed={false}
        href="/"
      />
    );

    const link = screen.getByText('Jobs');

    expect(link).toBeInTheDocument();
  });
});

Inconsistent useRouter behavior compared to the Next.js Router

If any of the router properties are accessed in a delayed fashion, if the route changes between the useRouter call and accessing the properties, then the original route's data is returned when using next-router-mock.

If the Next.js Router is used, the updated route's data is returned.

Example:

  const router = useRouter()
  useEffect(() => {
    const onRouteChange = (url) => {
      console.log('routeChangeComplete', router.query, router.asPath, url)
    }
    router.events.on('routeChangeComplete', onRouteChange)
    return () => {
      router.events.off('routeChangeComplete', onRouteChange)
    }
  }, [router])
  const routeChangeA = useCallback(() => {
    router.push('/path?x=A')
  })
  const routeChangeB = useCallback(() => {
    router.push('/path?x=B')
  })

Start at /path, then trigger routeChangeA and then routeChangeB. When using the Next.js Router, you'll get...

'routeChangeComplete' { x: 'A' } '/path?x=A' '/path?x=A'
'routeChangeComplete' { x: 'B' } '/path?x=B' '/path?x=B'

... but with next-router-mock you'll get...

'routeChangeComplete' {} '/path' '/path?x=A'
'routeChangeComplete' { x: 'A' } '/path?x=A' '/path?x=B'

Failed to install due to `postinstall` script on v0.7.3

Tring to install/upgrade to v0.7.3, npm install fails due to postinstall script added on 16dd116.

Does this necessary for users of this package?

$ npm i -D next-router-mock
npm ERR! code 2
npm ERR! path /home/mmyoji/tmp/node_modules/next-router-mock
npm ERR! command failed
npm ERR! command sh -c (cd test/next-10 && npm i); (cd test/next-11 && npm i); (cd test/next-12 && npm i); (cd test/next-canary && npm i)
npm ERR! sh: 1: cd: can't cd to test/next-10
npm ERR! sh: 1: cd: can't cd to test/next-11
npm ERR! sh: 1: cd: can't cd to test/next-12
npm ERR! sh: 1: cd: can't cd to test/next-canary

npm ERR! A complete log of this run can be found in:
npm ERR!     /home/mmyoji/.npm/_logs/2022-06-13T02_20_43_937Z-debug-0.log

Next 13.4.20-canary.20 issue

Any idea how to make the next-router-module work with the [email protected] or later?

I'm getting this error:

Cannot find module 'next/dist/shared/lib/router-context' from 'node_modules/next-router-mock/dist/MemoryRouterProvider/next-11.js'

    Require stack:
      node_modules/next-router-mock/dist/MemoryRouterProvider/next-11.js
      node_modules/next-router-mock/dist/MemoryRouterProvider/next-13.js
      node_modules/next-router-mock/dist/MemoryRouterProvider/index.js
      src/lib/testHelpers.tsx

Issue while running on next 12

Hi! ๐Ÿ‘‹

Firstly, thanks for your work on this project! ๐Ÿ™‚

Today I used patch-package to patch [email protected] for the project I'm working on.

The problem is that next does not export getRouteRegex and getRouteMatcher from theirs next/dist/shared/lib/router/utils
I am using the next@canary (18 currently)

Here is the diff that solved my problem:

diff --git a/node_modules/next-router-mock/dist/dynamic-routes/extensions-11.1.js b/node_modules/next-router-mock/dist/dynamic-routes/extensions-11.1.js
index 71b36de..b05f2b6 100644
--- a/node_modules/next-router-mock/dist/dynamic-routes/extensions-11.1.js
+++ b/node_modules/next-router-mock/dist/dynamic-routes/extensions-11.1.js
@@ -1,6 +1,10 @@
 "use strict";
 Object.defineProperty(exports, "__esModule", { value: true });
-const utils_1 = require("next/dist/shared/lib/router/utils");
+const utils = require("next/dist/shared/lib/router/utils");
+const regex = require("next/dist/shared/lib/router/utils/route-regex");
+const matcher = require("next/dist/shared/lib/router/utils/route-matcher");
+
+const utils_1 = { ...utils, ...regex, ...matcher }
 //
 const normalize_page_path_1 = require("next/dist/server/normalize-page-path");
 const MemoryRouter_registerPaths_1 = require("./MemoryRouter.registerPaths");
diff --git a/node_modules/next-router-mock/dist/dynamic-routes/extensions-12.js b/node_modules/next-router-mock/dist/dynamic-routes/extensions-12.js
index f5f78bd..211337c 100644
--- a/node_modules/next-router-mock/dist/dynamic-routes/extensions-12.js
+++ b/node_modules/next-router-mock/dist/dynamic-routes/extensions-12.js
@@ -1,6 +1,10 @@
 "use strict";
 Object.defineProperty(exports, "__esModule", { value: true });
-const utils_1 = require("next/dist/shared/lib/router/utils");
+const utils = require("next/dist/shared/lib/router/utils");
+const regex = require("next/dist/shared/lib/router/utils/route-regex");
+const matcher = require("next/dist/shared/lib/router/utils/route-matcher");
+
+const utils_1 = { ...utils, ...regex, ...matcher }
 // @ts-ignore
 const normalize_page_path_1 = require("next/dist/shared/lib/page-path/normalize-page-path");
 const MemoryRouter_registerPaths_1 = require("./MemoryRouter.registerPaths");
diff --git a/node_modules/next-router-mock/src/dynamic-routes/extensions-11.1.ts b/node_modules/next-router-mock/src/dynamic-routes/extensions-11.1.ts
index aae89ce..d2e46e0 100644
--- a/node_modules/next-router-mock/src/dynamic-routes/extensions-11.1.ts
+++ b/node_modules/next-router-mock/src/dynamic-routes/extensions-11.1.ts
@@ -1,10 +1,16 @@
 import {
-  getRouteMatcher,
-  getRouteRegex,
   getSortedRoutes,
   isDynamicRoute,
   //
 } from "next/dist/shared/lib/router/utils";
+import {
+  getRouteRegex
+  //
+} from "next/dist/shared/lib/router/utils/route-regex";
+import {
+  getRouteMatcher
+  //
+} from "next/dist/shared/lib/router/utils/route-matcher";
 //
 import { normalizePagePath } from "next/dist/server/normalize-page-path";
 
diff --git a/node_modules/next-router-mock/src/dynamic-routes/extensions-12.ts b/node_modules/next-router-mock/src/dynamic-routes/extensions-12.ts
index 5460ddc..77f0db0 100644
--- a/node_modules/next-router-mock/src/dynamic-routes/extensions-12.ts
+++ b/node_modules/next-router-mock/src/dynamic-routes/extensions-12.ts
@@ -1,10 +1,16 @@
 import {
-  getRouteMatcher,
-  getRouteRegex,
   getSortedRoutes,
   isDynamicRoute,
   //
 } from "next/dist/shared/lib/router/utils";
+import {
+  getRouteRegex
+  //
+} from "next/dist/shared/lib/router/utils/route-regex";
+import {
+  getRouteMatcher
+  //
+} from "next/dist/shared/lib/router/utils/route-matcher";
 // @ts-ignore
 import { normalizePagePath } from "next/dist/shared/lib/page-path/normalize-page-path";
 

This issue body was partially generated by patch-package.

Question: Nested component that has `useRouter` tests are taking much longer

I pose this as a question and not a bug.

I have a new nextjs instance (13) and I've setup two brief routes.

/pages/index.tsx
/pages/test/index.tsx

The first index, or root, is currently just a span of text. Test is running great.

The second page (test) has a few layout components, ie head, aside, main. I have a navigation link section in the head. The individual links have a useRouter hook for active styles.

I mock out the router since the hook will throw without context and run a simple expect test.

It works, the text is found within the layout and I'm happy, mostly.

The test is taking 15s to run. I have 0 external data at the moment, no async code to be found. I'm not currently testing route transitions just span text.

First test (passing, near instant)

import {render, screen} from '@testing-library/react'
import App from 'pages/index'

describe('App Landing', () => {
    test('Renders text', () => {
        render(<App />)

        expect(screen.getByText('This is some sort of login screen perhaps.', {exact: false})).toBeInTheDocument()
    })
})

Second test (passing, 15s delay)

import {render, screen} from 'test/test-utils'
import App from 'pages/test/index'

describe('Test Landing', () => {
    test.only('Renders the Test', () => {
        render(<App />)

        expect(screen.getByText('Test', {exact: false})).toBeInTheDocument()
    })
})

Both tests are very simple in asserting text. The difference between the pages again is the first is only a single span, and the second has presentation containers with a navigation container with link

<NavigationWrapper>
    <NavLink href="/test/1" title="One" />
    <NavLink href="/test/2" title="Two" disabled />
    <NavLink href="/test/3" title="Three" disabled />
    <NavLink href="/dash/4" title="Four" disabled />
</NavigationWrapper>

The NavLink component is just a next/link component with a useRouter hook to attach an active class for styles.

I'm just trying to see if anyone has experienced something like this and what you did to help solve it. I'm ok with it as is because it's technically working, but I would like to not rack up a lot of wasted cpu time once these tests make it to CI.

Any support planned for `next` version `13.2.x` ?

Hey hello,

Love the package, use it with Storybook.

However it does not seem to work with the latest version of next, at the time of this writing.

Are there any plans to add the missing support?

Fails on next 12.1.6

I'm upgrading my app from 12.1.2 to 12.1.6 and it seems some internal next paths have changed, causing the patching to fail.

When I run my tests:

    Cannot find module 'next/dist/server/normalize-page-path' from 'node_modules/next-router-mock/dist/dynamic-routes/extensions-11.1.js'

    Require stack:
      node_modules/next-router-mock/dist/dynamic-routes/extensions-11.1.js
      jest.setup.js

      at Resolver.resolveModule (node_modules/jest-resolve/build/resolver.js:324:11)
      at Object.<anonymous> (node_modules/next-router-mock/src/dynamic-routes/extensions-11.1.ts:9:1)

Edit: I narrowed it down a bit, with next 12.1.5 still works as expected.

Cannot use default (singleton) router: "You should only use "next/router" on the client side of your app"

Hello! First of all thanks for awesome package, @scottrippey!

I try to mock next-router with storybook. Is it real to mock default Router as we do it for useRouter?

For instance useRouter works fine:

useRouter example
import { useCallback } from 'react'
import { useRouter } from 'next/router'

const UseRouterPage = () => {
  const router = useRouter()

  const handleClick = useCallback(() => router.push({
      pathname: router?.pathname,
      query: {
        ...router?.query,
        test: '1'
      },
    }, undefined,
    {
      scroll: false,
      shallow: true
    }), [])

  return (
    <main>
      <button onClick={handleClick}>button</button>
    </main>
  )
}

export default UseRouterPage

But with default exported Router, the next error appears:

image

I try use default exported Router because in this case there is no component re-render.

useRouter example
import { useCallback } from 'react'
import Router from 'next/router'

const RouterPage = () => {
  const handleClick = useCallback(() => Router.push({
    pathname: Router?.pathname,
    query: {
      ...Router?.query,
      test: '1'
    },
  }, undefined,
  {
    scroll: false,
    shallow: true
  }), [])

  return (
    <main>
      <button onClick={handleClick}>button</button>
    </main>
  )
}

export default RouterPage

Repo to reproduce: https://github.com/sedlukha/next-router-mock-example

`next/link` not working with `passHref`

Hey there,

Spent a while trying many different things but ultimately I think there's something up with the behavior of next-router-mock when passHref is used with next/link. We use Stitches CSS to wrap the Link component.

The issue is the mockRouter just never updating.

Let me know if there's something you find here, I very well could be doing something wrong but I've exhausted all different things I could think to try.

const Breadcrumb = ({ history }: Props) => {
  const router = useRouter();
  return (
    <Navigation>
      <Arrow height={16} width={16} onClick={() => router.back()} name="ChevronLeft" />
      <List>
        {history.map((item) => {
          return (
            <Crumb key={item.id}>
              <Link passHref href={{ pathname: item.pathname, query: item.query }}> // next Link
                <CustomLink active={item.active}>{item.name}</CustomLink> // anchor tag
              </Link>
            </Crumb>
          );
        })}
      </List>
    </Navigation>
  );
};
jest.mock('next/router', () => jest.requireActual('next-router-mock'));
const history = [
    {
      pathname: '/admin/plans',
      query: null,
      name: 'Plans',
      id: 'plans',
      active: false,
    },
    {
      pathname: '/admin/plans',
      query: { planId: 1 },
      name: 'Plan 1',
      id: 'plan-1',
      active: true,
    },
  ];
test('clicking previous link should navigate back', () => {
    render(<Breadcrumb history={history} />, { wrapper: MemoryRouterProvider });
    const link = screen.getByRole('link', { name: 'Plans' });

    userEvent.click(link);

    expect(mockRouter).toMatchObject({
      asPath: '/admin/plans',
      pathname: '/admin/plans',
      query: {},
    });
  });

Screenshot 2023-08-10 at 7 58 30 AM

Next v12
next-router-mocker v0.9.8

Support router.push with optional pathname

Hi, i'am using this packages but i have one issue, maybe this not support router push with undefined pathname,

router.push({
  query: {
    five:5
  }
});

console.log(router.pathname) 
// i want return "/PATH/NAME?five=5"
// real "/?five=5"

it working in next-router-mock? ( i run add one test-case in your 'pushing URLs should update the route' test but not it's fail)

        await memoryRouter.push({
          query:{
            five: "5",
            four: "4"
          }
        })

        expect(memoryRouter).toMatchObject({
          asPath: "/one/two/three?four=4&five=5",
          pathname: "/one/two/three",
          query: {
            five: "5",
            four: "4",
          },
        })
"next": "12.1.0",
"next-router-mock": "^0.6.5",

thx

Add a changelog

Hello,

It would be nice if you could add a changelog, either via the Github releases page or via a CHANGELOG.md file.

Here's some guidance about how to format a changelog : https://keepachangelog.com/en/1.0.0/

There must some tools that can automate (part of) the work, I haven't looked into it though to find the one that fits your workflow best.

Thank you!

Failed to jest example code on Readme in Next12.1.6

Hello!

I've happened to runtime error with the testing readme.

import singletonRouter from 'next/router';
import NextLink from 'next/link';
import { render, fireEvent, screen, waitFor } from '@testing-library/react';

import mockRouter from 'next-router-mock';

jest.mock('next/router', () => require('next-router-mock'));
// This is needed for mocking 'next/link':
jest.mock('next/dist/client/router', () => require('next-router-mock'));

describe('next-router-mock', () => {
  beforeEach(() => {
    mockRouter.setCurrentUrl('/initial');
  });

  it('works with next/link', async () => {
    render(
      <NextLink href="/example?foo=bar">
        <a>Example Link</a>
      </NextLink>
    );
    fireEvent.click(screen.getByText('Example Link'));
    await waitFor(() => {
      expect(singletonRouter).toMatchObject({
        asPath: '/example?foo=bar',
        pathname: '/example',
        query: { foo: 'bar' },
      });
    });
  });
});

The test fails with the following error:

Error: Uncaught [TypeError: Cannot use 'in' operator to search for 'softPush' in null]

This error occurs with fireEvent.click
My environment follows:

  • next-router-mock: 0.7.4
  • Next: 12.1.6
  • React: 17.0.2
  • Jest: 28.1.3
  • jest-environment-jsdom: 28.1.3
  • @testing-library/jest-dom: 5.16.4
  • @testing-library/react": 12.1.5
  • @testing-library/user-event": 14.3.0

Using next-router-mock with class based components

Hello,

I'm trying to use next-router-mock to test class based components which are using withRouter().

My components looks like this:

import React from 'react'
import Head from 'next/head'
import {connect} from 'react-redux'
import {withRouter} from 'next/router'
import {WithRouterProps} from 'next/dist/client/with-router'

import {IRootState} from '../../store'

interface Props extends WithRouterProps {
}

interface State {
}

class View extends React.Component<Props, State> {
  render() {
    return (
      <div>
        <Head>
          <title>...</title>
        </Head>
      </div>
    )
  }
}

const mapStateToProps = (state: IRootState) => ({})

const mapDispatchToProps = {}

export default connect(mapStateToProps, mapDispatchToProps)(withRouter(View))

And my test looks like this:

import mockRouter from 'next-router-mock'
import configureStore from 'redux-mock-store'
import thunk from 'redux-thunk'
import renderer from 'react-test-renderer'
import {Provider} from 'react-redux'

import View from './View'

jest.mock('next/router', () => require('next-router-mock'))
jest.mock('next/dist/client/router', () => require('next-router-mock'))

const middlewares = [thunk]
const mockStore = configureStore(middlewares)

describe('View', () => {
  test('should match snapshot', () => {
    mockRouter.push('/xxx')

    const store = mockStore({...})

    const component = renderer.create((
      <Provider store={store}>
        <View/>
      </Provider>
    ))

    let tree = component.toJSON()

    expect(tree).toMatchSnapshot()
  })
})

When I try to run it, it fails:

 FAIL  View.test.tsx
  โ— Test suite failed to run

    TypeError: (0 , _router.withRouter) is not a function

As I see there is no reference of withRouter() in the next-router-mock source, so I guess it does not support this.

Can you help me with any workaround? I guess I have to write my own mock code of withRouter() ? Or can you please implement this?

Thank you!

In 0.9.3 test asserting `window.location.assign` fails

Hello, when I bump from 0.9.2 to 0.9.3 I have a test like this that is now failing. Test is stripped down a bit.

const token = 'myToken'
const redirectUrl = 'myRedirection'

window.localStorage.setItem('accessToken', token)

mockRouter.setCurrentUrl({
  pathname: Routes.WorkerLogin,
  query: { redirectUrl },
})

const { user } = await render()

await editPhoneInput(user, '0625045131')
await editPasswordInput(user, '1234')

await clickSignInButton(user)

await waitFor(() => {
  expect(window.location.assign).toHaveBeenCalledTimes(1)
})
Error: expect(window.location.assign).toHaveBeenCalledTimes(expected)

Expected number of calls: 1
Received number of calls: 0

Using `next/link` with the locale property.

Hi, I have a language selector where I render every <NextLink /> passing the property locale so the URL uses the correct locale. But this is not being reflected and actually ignored by Link.

I was expecting that

<Link href={{ pathname: "/asdf", query: { test: "1234" }} locale="en" />

to result in something like /en/asdf?test=1234, but it is omitting the /en part.

Any ideas what part of the next/link I may need to mock to be able to test this?

How to mock next router with jest `experimental-vm-modules`

I've been trying a ton of different ways but nothing i try seems to work. Any ideas or suggestions would be greatly appreciated.

// Test file
import React from "react";
import { render, screen } from "@accolade-x/test-utils";
import { jest } from "@jest/globals";

jest.unstable_mockModule("next/router", () => require("next-router-mock"));

describe("BackButton", () => {
  it("should render an button tag", async () => {
    const { BackButton } = await import("./BackButton");
    render(<BackButton />);
    expect(await screen.findByRole("button")).toBeInTheDocument();
  });
});
// Component file
export const BackButton = ({
  onClick,
  ...rest
}: BackButtonProps) => {
  const router = useRouter();
  const clickHandler: MouseEventHandler<HTMLButtonElement> = (e) => {
    if (onClick) {
      onClick(e);
    }
    router.back();
  };
  return (
    <Button onClick={clickHandler} {...rest}>
      Back
    </Button>
  );
};

Support for i18n defaultLocale

Hello ๐Ÿ‘‹

Is it possible to have the defaultLocale property support?

For example:

const {defaultLocale} = useRouter();

Then in our tests, we can set the default locale like this:

import routerMock from 'next-router-mock';

routerMock.defaultLocale = 'en';

It would be really appreciated!

Property 'registerPaths' does not exits on type 'MemoryRouter'.

Hey,
I have just updated your package from v0.6.3 to v0.6.9 and I have a typescript error when I use registerPaths
Here's my code:

import memoryRouter from "next-router-mock";
import "next-router-mock/dynamic-routes/next-12";

memoryRouter.registerPaths([PRODUCTS, PRODUCTS + "/[...params]"]);

I also should mention that the next version I am using is v12.1.7-canary.16

I think something has changed between these versions and typescript is not able to get the right types

router.push({ hash }) not triggering a re-render

Hi there!

I was playing around with mock router and found this peculiar edge case, maybe I missing something.

jest.mock('next/router', () => require('next-router-mock'));

const ExampleComponent = ({ href = '' }) => {
  const router = useRouter();
  return (
    <button onClick={() => router.push({ hash: `#${href}` })}>
      The current route is: "{router.asPath}"
    </button>
  );
};

describe('next-router-mock', () => {
  it('mocks the useRouter hook', () => {
    // Set the initial url:
    mockRouter.push('/initial-path');

    // Render the component:
    render(<ExampleComponent href="test" />);
    expect(screen.getByRole('button')).toHaveTextContent(
      'The current route is: "/initial-path"',
    );

    // Click the button:
    fireEvent.click(screen.getByRole('button'));

    // Ensure the router was updated:
    expect(mockRouter).toMatchObject({
      asPath: '/initial-path#test',
      pathname: '/initial-path',
    });

    // THIS WILL THROW
    expect(screen.getByRole('button')).toHaveTextContent(
      'The current route is: "/initial-path#test"',
    );
  });
});

The error:

Expected element to have text content:
  The current route is: "/initial-path#test"
Received:
  The current route is: "/initial-path"

Apparently when we update just the hash the asPath is not updating in the component (although in next it does)

Mac OS Ventura 13.4
[email protected]
[email protected]
[email protected]

Mock router doesn't update with `userEvent`

Background

Currently, I am using this library to run testing on our app. However, I seems not being able to make it work with userEvent. I apologise beforehand if this is a known issue.

Problems

Render with NextLink and try clicking the link using userEvent will cause the test to fail.

Expectation

Mock router asPath value to be updated with the URL href value.

Actual

Mock router asPath doesn't changed even though click has been triggered.

Repro

https://codesandbox.io/p/sandbox/next-jest-rtl-qs1w9l

next-router-mock doesn't support Next.js 11

next-router-mock doesn't support Next.js 11. When running npm install:

npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR!
npm ERR! Found: [email protected]
npm ERR! node_modules/next
npm ERR!   next@"11.0.0" from the root project
npm ERR!
npm ERR! Could not resolve dependency:
npm ERR! peer next@"^10.0.0" from [email protected]

dist folder auto-import inconsistencies

Howdy! Great lib! I've been using it these past few days and really like it, thanks for making it. โค๏ธ โค๏ธ โค๏ธ

One issue I was running into was the auto-import suggestion for createDynamicRouteParser does not recommend what you recommend in the example, next-router-mock/dynamic-routes, it wants to import from a subfolder of dist/

Screenshot 2023-04-18 at 3 04 56 pm

Have you considered bundling your dist folder? For example, I've used tsup on a few projects and it works well. You can use package.types to point to a bundled dist/index.d.ts as well. That way everything always exports from next-router-mock. If you are interested, and I have time, I can try to throw up a PR. Let me know. ๐Ÿ˜„

If bundling is not feasible due to complications I'm not aware of, perhaps another strategy is possible, like an explicit re-exporting from an dist/dynamic-routes/index.ts, that way the nextjs-versioned exports are still accessible via the dist subfolders, but the default export is in a more "intuitive" location.

Let me know what you think. And, one more time, thanks for the lib! โค๏ธ โค๏ธ โค๏ธ

Reference of `router` returned from `useRouter` is not preserved

The reference of router returned from useRouter is not preserved.
This differs from the actual behavior of Next.js, where the singleton router is returned from useRouter (thus preserving the reference).

The actual behavior of Next.js is that they make a subscription to the router's update and triggers the re-render of the page. Since the props object is created every time, the page component effectively re-renders every time.

In contrast, next-router-mock always creates a new instance of the router. When using useEffect with router in the deps, this results in an infinite loop. (In actual next.js, the app functions as normal)

Modify the as param condition

Hi!

I have something to suggest while using it, so I am registering an issue.
Can I change the condition of as parameter to falsy values other than undefined?

if (as === undefined) {
asRoute = undefined;
asPath = getRouteAsPath(newRoute.pathname, newRoute.query, newRoute.hash);

I wish change

if (!as) {
      asRoute = undefined;
      asPath = getRouteAsPath(newRoute.pathname, newRoute.query, newRoute.hash);

What do you think? Have a good day ๐Ÿ™‚

Bug with Mock Router when pushing query changes:

ATM it looks like something strange is happening when the mock router fires the onPush event for query changes.

a tested component does:

import { useRouter } from 'next/router';
import qs from 'qs';
...
... inside of component's render:
const router = useRouter();
router.push(
      {
        pathname: '/moo-cow',
        query: qs.stringify({ moo: true}, {
          encode: false,
        }),
      },
    );

but when the tests run, i get this:

Timed out retrying after 4000ms: expected pushStub to have been called with arguments matching 
{ query: { moo: true }}

The following calls were made:
pushStub("/moo-cow?0=m&1=o&2=o&3=%3D&4=t&5=r&6=u&7=e", {shallow: false})

For some reason the query params are parsed erroneously inside of the router. (eg ?0=m&1=o&2=o&3=%3D&4=t&5=r&6=u&7=e instead of ?moo=true

Consider the skipTrailingSlashRedirect config

In my next.config.js I have skipTrailingSlashRedirect: true, i.e. the URLs should retain their trailing slash. next-router-mock however seems to trim the trailing slash from all URLs.

This fails:

// Component
router.push('/foo/')

// Test
const spy = jest.fn()
render(<MemoryRouterProvider onPush={spy}><Component /></MemoryRouterProvider)
expect(spy).toHaveBeenCalledWith('/foo/') // Instead, it is called with /foo

I'm able to fix this by patching the package (I changed normalizeTrailingSlash()), but it would be cool to have first class support.

Support Dynamic Routes with Next v12 (Cannot find module 'next/dist/server/normalize-page-path')

hello, i have this error :

Test suite failed to run

    Cannot find module 'next/dist/server/normalize-page-path' from 'node_modules/next-router-mock/dist/dynamic-routes/extensions-11.1.js'

    Require stack:
      node_modules/next-router-mock/dist/dynamic-routes/extensions-11.1.js
      components/Breadcrumb/__tests__/BreadcrumbActu.test.js

      at Resolver._throwModNotFoundError (node_modules/jest-resolve/build/resolver.js:491:11)
      at Object.<anonymous> (node_modules/next-router-mock/src/dynamic-routes/extensions-11.1.ts:9:1)

My version of next.js : "12.1.6"

Issue with next/link in Next >12.2.0, 13.*

Hello!

I've noticed that after upgrade to newest version of Next 12.2.0 (released 3 days ago) there is an issue with tests utilising Next Link.

import Link from "next/link"
...
jest.mock("next/router", () => require("next-router-mock"));
jest.mock("next/dist/client/router", () => require("next-router-mock"));
...
it("", () => {
  const { getByText } = render(<div><Link href={"/foo"}>Foo</Link></div>);
  const foo = getByText("Foo");
  fireEvent.click(foo);
});
...

test fails with following error:

TypeError: Cannot read properties of null (reading 'push')
57 | fireEvent.click(foo);

After Next downgrade to previous stable version (12.1.6) everything works fine.

I am on the latest version of next-router-mock

I suspected that there may be some changes in the paths or refactor of Link component in the 12.2.0 release but didn't found anything like that in the PR. Do you have any clue what's going on?

Best!

Can't perform a React state update on an unmounted component

Hi,

first of all, thanks for providing this library! I have no idea one should write integration tests for Next.js without it ๐Ÿค”

I've written a couple of tests for a Next.js page component, but even though all tests basically render the same, only one test throws this warning:

    console.error
      Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
          at Link (C:\Users\{project}\node_modules\next\client\link.tsx:131:19)
          at LinkIconButton (C:\Users\{project}\libs\ui\src\lib\button.tsx:61:23)
          at div
          at td
          at TCell (C:\Users\{project}\libs\ui\src\lib\table\table.tsx:59:78)
          at tr
          at TRow (C:\Users\{project}\libs\ui\src\lib\table\table.tsx:37:87)
          at AufgabenListItem (C:\Users\{project}\apps\sales-planner\src\components\aufgaben-list\aufgaben-list-item.tsx:18:36)

      at printWarning (../../node_modules/react-dom/cjs/react-dom.development.js:67:30)
      at error (../../node_modules/react-dom/cjs/react-dom.development.js:43:5)
      at warnAboutUpdateOnUnmountedFiberInDEV (../../node_modules/react-dom/cjs/react-dom.development.js:23914:9)
      at scheduleUpdateOnFiber (../../node_modules/react-dom/cjs/react-dom.development.js:21840:5)
      at dispatchAction (../../node_modules/react-dom/cjs/react-dom.development.js:16139:5)
      at handleRouteChange (../../node_modules/next-router-mock/src/useMemoryRouter.tsx:24:7)
      at ../../node_modules/next-router-mock/src/lib/mitt/index.ts:38:9
          at Array.map (<anonymous>)

I tried to create a minimal reproduction of the issue, but I really struggle to pinpoint the underlying problem. But I noticed one thing which probably is the cause.

I modified the code of useMemoryRouter to output some log statements:

// Trigger updates on route changes:
useEffect(() => {
  const id = lodash.uniqueId();
  console.log(`subscribe: ${id}`);
  const handleRouteChange = () => {
    console.log(`handleRouteChange: ${id}`);
    // Ensure the reference changes each render:
    setRouter(MemoryRouter.snapshot(singletonRouter));
  };

  singletonRouter.events.on("routeChangeComplete", handleRouteChange);
  return () => {
    console.log(`UNsubscribe: ${id}`);
    singletonRouter.events.off("routeChangeComplete", handleRouteChange);
  };
}, [singletonRouter]);

Basically, it logs when useMemoryRouter subscribes and unsubscribes to routeChangeComplete and also logs every call of handleRouteChange. And each subscription gets a unique ID.

The interesting thing is this: In the following excerpt of my test log, there is a handleRouteChange execution for Subscription 7 even though the same subscription has already been unsubscribed. That probably explains why react complains about a state update on an unmounted component.

    console.log
      UNsubscribe: 7

      at ../../node_modules/next-router-mock/src/useMemoryRouter.tsx:28:25

    console.log
      UNsubscribe: 6

      at ../../node_modules/next-router-mock/src/useMemoryRouter.tsx:28:25

    console.log
      handleRouteChange: 5

      at handleRouteChange (../../node_modules/next-router-mock/src/useMemoryRouter.tsx:22:5)
          at Array.map (<anonymous>)

    console.log
      handleRouteChange: 6

      at handleRouteChange (../../node_modules/next-router-mock/src/useMemoryRouter.tsx:22:5)
          at Array.map (<anonymous>)

    console.error
      Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
          at Link (C:\Users\Marvin\Projekte\tbit\oneplatform\node_modules\next\client\link.tsx:131:19)
          at LinkIconButton (C:\Users\Marvin\Projekte\tbit\oneplatform\libs\ui\src\lib\button.tsx:61:23)
          at div
          at td
          at TCell (C:\Users\Marvin\Projekte\tbit\oneplatform\libs\ui\src\lib\table\table.tsx:59:78)
          at tr
          at TRow (C:\Users\Marvin\Projekte\tbit\oneplatform\libs\ui\src\lib\table\table.tsx:37:87)
          at AufgabenListItem (C:\Users\Marvin\Projekte\tbit\oneplatform\apps\sales-planner\src\components\aufgaben-list\aufgaben-list-item.tsx:18:36)

      at printWarning (../../node_modules/react-dom/cjs/react-dom.development.js:67:30)
      at error (../../node_modules/react-dom/cjs/react-dom.development.js:43:5)
      at warnAboutUpdateOnUnmountedFiberInDEV (../../node_modules/react-dom/cjs/react-dom.development.js:23914:9)
      at scheduleUpdateOnFiber (../../node_modules/react-dom/cjs/react-dom.development.js:21840:5)
      at dispatchAction (../../node_modules/react-dom/cjs/react-dom.development.js:16139:5)
      at handleRouteChange (../../node_modules/next-router-mock/src/useMemoryRouter.tsx:24:7)
      at ../../node_modules/next-router-mock/src/lib/mitt/index.ts:38:9
          at Array.map (<anonymous>)

    console.log
      handleRouteChange: 7

      at handleRouteChange (../../node_modules/next-router-mock/src/useMemoryRouter.tsx:22:5)
          at Array.map (<anonymous>)

    console.error
      Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
          at AufgabenListItem (C:\Users\Marvin\Projekte\tbit\oneplatform\apps\sales-planner\src\components\aufgaben-list\aufgaben-list-item.tsx:18:36)

      at printWarning (../../node_modules/react-dom/cjs/react-dom.development.js:67:30)
      at error (../../node_modules/react-dom/cjs/react-dom.development.js:43:5)
      at warnAboutUpdateOnUnmountedFiberInDEV (../../node_modules/react-dom/cjs/react-dom.development.js:23914:9)
      at scheduleUpdateOnFiber (../../node_modules/react-dom/cjs/react-dom.development.js:21840:5)
      at dispatchAction (../../node_modules/react-dom/cjs/react-dom.development.js:16139:5)
      at handleRouteChange (../../node_modules/next-router-mock/src/useMemoryRouter.tsx:24:7)
      at ../../node_modules/next-router-mock/src/lib/mitt/index.ts:38:9
          at Array.map (<anonymous>)

It seems that there's a short window where the MittEmitter behind singletonRouter.events still executes some event handlers that shouldn't be there anymore at that point.

I validated this with this dirty hack which actually solves the issue:

  useEffect(() => {
    let isUnsubscribed = false;
    const handleRouteChange = () => {
      if (!isUnsubscribed) {
        // Ensure the reference changes each render:
        setRouter(MemoryRouter.snapshot(singletonRouter));
      }
    };

    singletonRouter.events.on("routeChangeComplete", handleRouteChange);
    return () => {
      isUnsubscribed = true;
      singletonRouter.events.off("routeChangeComplete", handleRouteChange);
    }
  }, [singletonRouter]);

Im aware that it's unfortunate, that I cannot provide a reproduction for this issue, but the project I'm working on is proprietary and my attempts to extract the issue have failed so far.

Missing Hash events

Hey there

the memory router helped a lot to create snapshot even for complex components in JEST โค๏ธ

unfortunately the hash routing events are not supported

we will try to prepare a new pr tomorrow

Router.push "as" parameter not working

Hi @scottrippey,

thanks for providing this library! We are currently facing the issue that we want to test the following code using the library:

const pathWithParams = '/our/path?with=params';
const pathWithoutParams = '/our/path'

router.push(pathWithParams, pathWithoutParams);

We write our assertion as follows:

expect(SingletonRouter).toMatchObject({
  pathname: '/our/path',
  asPath: '/our/path',
  query: {
    with: 'params',
  },
});

However, this assertion will fail, as the asPath property will have the value: /our/path?with=params. In our opinion, this is wrong as the asPath property should have the same value that is passed as the second parameter of the push (or replace) function.

After looking at the code, we found the following function:

private async _setCurrentUrl(

This faction receives an as parameter (e.g. from the push) function. However, this parameter is never used in the function. Instead to compute the asPath property, the following line is used:
const asPath = getRouteAsPath(newRoute.pathname, newRoute.query, newRoute.hash);

In our opinion, this should be changed to

const asPath = as ?? getRouteAsPath(newRoute.pathname, newRoute.query, newRoute.hash);

(note the as ?? part). To make sure the functionality matches the actual functionality from the Next Router. By implementing it this way, the as parameter will be used if it is defined and if it is not defined, it will fall back to the current functionality.

See the linked PR for our approach on how to solve this.

What do you think? Is this reasoning valid? Should we open a PR or would you rather add it yourself?

Cheers ๐Ÿ‘‹

feat request: drop support for nextjs 10.x

hi :)

would it be possible to drop next 10 in a major update?

Vite is not able to compile next-router-mock as it can't resolve imports inside src/MemoryRouterProvider/next-10.tsx

configuring webpack alias in storybook, it doesn't to work in storybook test

Hi,
When I use it after configuring webpack alias in storybook, it doesn't seem to work in storybook test.


spec
next 12.2.5
storybook 6.5

I read the readme and set it up as below.
https://github.com/scottrippey/next-router-mock#storybook-configuration
https://github.com/scottrippey/next-router-mock#storybook-example

I'm using storybook interaction test as my testing tool

My code

// component.tsx
import qs from 'qs';
import Link from 'next/link';
import { useRouter } from 'next/router';

const WithNextRouter = () => {
  const router = useRouter();
  const { pathname, asPath, query } = router;
  const onClickQueryButton = () =>
    router.push('/test?query=1', null, { shallow: true });

  return (
    <div>
      <Link href="/test">home</Link>
      <br />
      <Link href="/test/abc">a</Link>
      <br />
      <button type="button" onClick={onClickQueryButton}>
        query
      </button>
      <ul>
        <li>pathname: {pathname}</li>
        <li>asPath: {asPath}</li>
        <li>query: {qs.stringify(query)}</li>
      </ul>
    </div>
  );
};

export default WithNextRouter;
// component.stories.tsx
export default {
  title: 'With Next Router',
  component: WithNextRouterComponent,
  parameters: {
    url: {
      pathname: '/test',
      asPath: '/test',
      query: {
        param1: 1,
        param2: 2,
      },
    },
    jsx: {
      skip: 1,
      displayName: () => 'WithNextRouterComponent',
    },
  },
} as ComponentMeta<typeof WithNextRouterComponent>;

export const WithNextRouter: ComponentStory<
  typeof WithNextRouterComponent
> = () => <WithNextRouterComponent />;

WithNextRouter.play = async ({
  canvasElement,
}) => {
  const canvas = within(canvasElement);
  
  await step('show pathname', async () => {
    // Given
    const pathnameElement = canvas.getByText(/pathname:/);

    // Then
    await expect(pathnameElement).toBeInTheDocument();
    await expect(pathnameElement.textContent).toBe('pathname: /test');
  });

  await step('click on abc link displays the relevant information.', async () => {
    // Given
    const linkElement = canvas.getByRole('link', { name: /abc/i });
    const pathnameElement = canvas.getByText(/pathname:/);
    const asPathElement = canvas.getByText(/asPath:/);

    // When
    await userEvent.click(linkElement);

    // Then
    await expect(pathnameElement.textContent).toBe(
      'pathname: /test/abc'
    );
    await expect(asPathElement.textContent).toBe('asPath: /test/abc');
  });
}

First in โ€˜show pathnameโ€™, the test is conducted by setting the initial url parameters.
The expected result is โ€˜/testโ€™, but the actual result is โ€˜/โ€™.

Second, โ€˜click on abc link displays the relevant information.โ€™ is a test when a click event occurs through next/link.
The expected result is '/test/abc', but the actual result is '/'.

If you use the storybook test tool after configuring webpack, it will not work.


If I don't configure webpack alias, it works normally. Do you know why?
Any help would be appreciated.

Usage with `next/link`

First of all thank you so much for this library. Do you know how we can use it along with next/link? For example, clicking on a link and then checking the pathname? I somehow managed to make it work. Bit hacky for now:

// jest.setup.js

jest.mock('next/router', () => {
  const router = require('next-router-mock');
  const i18nConfig = require('./next-i18next.config');

  router.default.locales = i18nConfig.i18n.locales;
  router.default.locale = i18nConfig.i18n.defaultLocale;

  return router;
});

jest.mock('next/link', () => {
  const { cloneElement } = require('react');
  const router = require('next-router-mock');

  return ({ children, href, replace, as, shallow, locale, scroll }) => {
    const onClick = () =>
      router.default[replace ? 'replace' : 'push'](href, as, {
        shallow,
        locale,
        scroll,
      });

    return cloneElement(children, {
      href,
      onClick,
    });
  };
});

and then doing expect(router.pathname).toBe('/path/name'); in my tests.

Only problem I can see here is around resetting the pathname, query, asPath etc for router object for every test in that particular test file.

Does not support hash routes

In next/router proper, I am seeing asPath values that include the URL hash as I expect. However, passing hashes to next-router-mock is removing hashes. It looks like the pathing logic only deals with pathname and query but doesn't preserve hash so my tests are "passing" even though at runtime the behavior is different (and failing) causing a false-positive test suite.

router.push('/page#hash=true');
router.push(new URL('/page#hash=true', 'https://www.google.com'));

console.log(asPath);
// logs: "/page"

MemoryRouterProvider url property does not work properly

I'm trying to text links with this package and I am getting inconsistent behavior.

I defined a custom render as follows:

  const mockPath = "/streaming";

  const mockItem = {
    label: "Live",
    path: mockPath,
    //decorator: "streaming-status",
  };

const renderWithRouter = (ui: React.ReactElement, { route = "/" } = {}) => {
  const wrapper = ({ children }: { children: React.ReactNode }) => (
    <MemoryRouterProvider url={route}>{children}</MemoryRouterProvider>
  );
  return {
    user: userEvent.setup(),
    ...render(ui, { wrapper }),
  };
};

And I'm using it on my test like this:

  const setup = () => {
    const view = renderWithRouter(
      <Navbar>
        <HeaderItemBase {...mockItem} />
      </Navbar>,
      { route: mockItem.path }
    );

    return view;
  };


  it("should have blue text color when route is same with path", async () => {
    const view = setup();
    expect(view).toBeTruthy();

    const { user } = view;

    const link = screen.getByRole("link", { name: mockItem.label });

    await user.click(link);

    console.log("Current Path", mockRouter.asPath);
    expect(mockRouter.asPath).toStrictEqual(mockPath);

    /** TODO
     * `next/navigation` is not fully suported on the mocking library yet.
     * https://github.com/scottrippey/next-router-mock/issues/67
     * expect(link).toHaveClass("text-primary-400");
     *  */
  });

Logging the router path we get:

17:32:15 | header item base > should have white text color when route is different to path | stdout

This is the route /streaming
Current Path /

17:32:15 | header item base > should have blue text color when route is same with path | stdout

This is the route /streaming
Current Path /

17:32:16 | header item base > should have blue text color when route is same with path | stdout

Current Path after Click /

Yeah, it should be "Current Path /streaming".

Also, after clicking on the button, it should navigate easily, but it seems the route is always overwritten to be the given one and it does not change.

When using it without url property it works well, and navigates correctly.

It seems I got the property wrong, it should work as an initial route, right? Could you write an example of writing it as a provider with options using testing library?

MemoryRouterProvider/index.d.ts' is not a module.

I see the error since v0.7.0.

error TS2306: File '/Users/yusukegoto/src/myapp/node_modules/next-router-mock/dist/MemoryRouterProvider/index.d.ts' is not a module.

And as error mesage said, index.d.js is empty.

ls -l ./node_modules/next-router-mock/dist/MemoryRouterProvider/index.d.ts
-rw-r--r--  1 yusukegoto  staff  0 10 Jun 15:57 ./node_modules/next-router-mock/dist/MemoryRouterProvider/index.d.ts

I import it like below. This is the same one written in README.

import { MemoryRouterProvider } from 'next-router-mock/MemoryRouterProvider';

Am I missing some configuration?

support for i18n locale

type: feature request

Use case:
I am testing my i18n components. I need the locale support in the useRouter hook.

const { locale, locales } = useRouter()

I can work and submit a PR if you are ok with it

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.