Files
sentinel/static/app/utils/withDomainRequired.spec.tsx
2024-02-15 17:01:50 +00:00

401 lines
13 KiB
TypeScript

import type {RouteComponentProps} from 'react-router';
import type {Location, LocationDescriptor, LocationDescriptorObject} from 'history';
import {LocationFixture} from 'sentry-fixture/locationFixture';
import {OrganizationFixture} from 'sentry-fixture/organization';
import {initializeOrg} from 'sentry-test/initializeOrg';
import {render, screen} from 'sentry-test/reactTestingLibrary';
import withDomainRequired, {normalizeUrl} from 'sentry/utils/withDomainRequired';
describe('normalizeUrl', function () {
let result;
beforeEach(function () {
window.__initialData = {
customerDomain: {
subdomain: 'albertos-apples',
organizationUrl: 'https://albertos-apples.sentry.io',
sentryUrl: 'https://sentry.io',
},
} as any;
});
it('replaces paths in strings', function () {
const location = LocationFixture();
const cases = [
// input, expected
['/settings/', '/settings/'],
['/accept-terms/acme/', '/accept-terms/'],
// Organization settings views.
['/settings/acme/', '/settings/organization/'],
['/settings/organization', '/settings/organization/'],
['/settings/sentry-organizations/members/', '/settings/members/'],
['/settings/sentry-organizations/members/3/', '/settings/members/3/'],
['/settings/sentry-organizations/teams/peeps/', '/settings/teams/peeps/'],
['/settings/sentry-organizations/teams/payments/', '/settings/teams/payments/'],
['/settings/sentry-organizations/billing/receipts/', '/settings/billing/receipts/'],
[
'/settings/sentry-organizations/teams/test-organizations/notifications/',
'/settings/teams/test-organizations/notifications/',
],
[
'/settings/acme/developer-settings/release-bot/',
'/settings/developer-settings/release-bot/',
],
[
'/settings/sentry-organizations/integrations/vercel/12345/?next=something',
'/settings/integrations/vercel/12345/?next=something',
],
// Account settings should stay the same
['/settings/account/', '/settings/account/'],
['/settings/account/security/', '/settings/account/security/'],
['/settings/account/details/', '/settings/account/details/'],
['/join-request/acme', '/join-request/'],
['/join-request/acme/', '/join-request/'],
['/onboarding/acme/', '/onboarding/'],
['/onboarding/acme/project/', '/onboarding/project/'],
['/organizations/new/', '/organizations/new/'],
['/organizations/albertos-organizations/issues/', '/issues/'],
[
'/organizations/albertos-organizations/issues/?_q=all#hash',
'/issues/?_q=all#hash',
],
['/acme/project-slug/getting-started/', '/getting-started/project-slug/'],
[
'/acme/project-slug/getting-started/python',
'/getting-started/project-slug/python',
],
['/settings/projects/python/filters/', '/settings/projects/python/filters/'],
['/settings/projects/onboarding/abc123/', '/settings/projects/onboarding/abc123/'],
[
'/settings/projects/join-request/abc123/',
'/settings/projects/join-request/abc123/',
],
[
'/settings/projects/python/filters/discarded/',
'/settings/projects/python/filters/discarded/',
],
[
'/settings/projects/getting-started/abc123/',
'/settings/projects/getting-started/abc123/',
],
// Team settings links in breadcrumbs can be pre-normalized from breadcrumbs
['/settings/teams/peeps/', '/settings/teams/peeps/'],
[
'/settings/billing/checkout/?_q=all#hash',
'/settings/billing/checkout/?_q=all#hash',
],
[
'/settings/billing/bundle-checkout/?_q=all#hash',
'/settings/billing/bundle-checkout/?_q=all#hash',
],
];
for (const [input, expected] of cases) {
result = normalizeUrl(input);
expect(result).toEqual(expected);
result = normalizeUrl(input, location);
expect(result).toEqual(expected);
result = normalizeUrl(input, {forceCustomerDomain: false});
expect(result).toEqual(expected);
result = normalizeUrl(input, location, {forceCustomerDomain: false});
expect(result).toEqual(expected);
}
// Normalizes urls if options.customerDomain is true and orgslug.sentry.io isn't being used
window.__initialData.customerDomain = null;
for (const [input, expected] of cases) {
result = normalizeUrl(input, {forceCustomerDomain: true});
expect(result).toEqual(expected);
result = normalizeUrl(input, location, {forceCustomerDomain: true});
expect(result).toEqual(expected);
}
// No effect if customerDomain isn't defined
window.__initialData.customerDomain = null;
for (const [input, _expected] of cases) {
result = normalizeUrl(input);
expect(result).toEqual(input);
result = normalizeUrl(input, location);
expect(result).toEqual(input);
}
});
it('replaces pathname in objects', function () {
const location = LocationFixture();
result = normalizeUrl({pathname: '/settings/acme/'}, location);
expect(result.pathname).toEqual('/settings/organization/');
result = normalizeUrl({pathname: '/settings/acme/'}, location, {
forceCustomerDomain: false,
});
expect(result.pathname).toEqual('/settings/organization/');
result = normalizeUrl({pathname: '/settings/sentry/members'}, location);
expect(result.pathname).toEqual('/settings/members');
result = normalizeUrl({pathname: '/organizations/albertos-apples/issues'}, location);
expect(result.pathname).toEqual('/issues');
result = normalizeUrl(
{
pathname: '/organizations/sentry/profiling/profile/sentry/abc123/',
query: {sorting: 'call order'},
},
location
);
expect(result.pathname).toEqual('/profiling/profile/sentry/abc123/');
result = normalizeUrl(
{
pathname: '/organizations/albertos-apples/issues',
query: {q: 'all'},
},
location
);
expect(result.pathname).toEqual('/issues');
// Normalizes urls if options.customerDomain is true and orgslug.sentry.io isn't being used
window.__initialData.customerDomain = null;
result = normalizeUrl({pathname: '/settings/acme/'}, location, {
forceCustomerDomain: true,
});
expect(result.pathname).toEqual('/settings/organization/');
result = normalizeUrl(
{
pathname: '/organizations/albertos-apples/issues',
query: {q: 'all'},
},
location,
{
forceCustomerDomain: true,
}
);
expect(result.pathname).toEqual('/issues');
});
it('replaces pathname in function callback', function () {
const location = LocationFixture();
function objectCallback(_loc: Location): LocationDescriptorObject {
return {pathname: '/settings/'};
}
result = normalizeUrl(objectCallback, location);
expect(result.pathname).toEqual('/settings/');
function stringCallback(_loc: Location): LocationDescriptor {
return '/organizations/a-long-slug/discover/';
}
result = normalizeUrl(stringCallback, location);
expect(result).toEqual('/discover/');
// Normalizes urls if options.customerDomain is true and orgslug.sentry.io isn't being used
window.__initialData.customerDomain = null;
function objectCallback2(_loc: Location): LocationDescriptorObject {
return {pathname: '/settings/'};
}
result = normalizeUrl(objectCallback2, location, {forceCustomerDomain: true});
expect(result.pathname).toEqual('/settings/');
function stringCallback2(_loc: Location): LocationDescriptor {
return '/organizations/a-long-slug/discover/';
}
result = normalizeUrl(stringCallback2, location, {forceCustomerDomain: true});
expect(result).toEqual('/discover/');
});
it('errors on functions without location', function () {
function objectCallback(_loc: Location): LocationDescriptorObject {
return {pathname: '/settings/organization'};
}
expect(() => normalizeUrl(objectCallback)).toThrow();
});
});
const originalLocation = window.location;
describe('withDomainRequired', function () {
type Props = RouteComponentProps<{orgId: string}, {}>;
function MyComponent(props: Props) {
const {params} = props;
return <div>Org slug: {params.orgId ?? 'no org slug'}</div>;
}
beforeEach(function () {
Object.defineProperty(window, 'location', {
writable: true,
value: {
replace: jest.fn(),
pathname: '/organizations/albertos-apples/issues/',
search: '?q=123',
hash: '#hash',
},
});
window.__initialData = {
customerDomain: {
subdomain: 'albertos-apples',
organizationUrl: 'https://albertos-apples.sentry.io',
sentryUrl: 'https://sentry.io',
},
links: {
organizationUrl: null,
regionUrl: null,
sentryUrl: 'https://sentry.io',
},
} as any;
});
afterEach(function () {
window.location = originalLocation;
});
it('redirects to sentryUrl in non-customer domain world', function () {
window.__initialData = {
customerDomain: null,
features: ['organizations:customer-domains'],
links: {
organizationUrl: null,
regionUrl: null,
sentryUrl: 'https://sentry.io',
},
} as any;
const organization = OrganizationFixture({
slug: 'albertos-apples',
features: [],
});
const params = {
orgId: 'albertos-apples',
};
const {router, route, routerContext} = initializeOrg({
organization,
router: {
params,
},
});
const WrappedComponent = withDomainRequired(MyComponent);
const {container} = render(
<WrappedComponent
router={router}
location={router.location}
params={params}
routes={router.routes}
routeParams={router.params}
route={route}
/>,
{context: routerContext}
);
expect(container).toBeEmptyDOMElement();
expect(window.location.replace).toHaveBeenCalledTimes(1);
expect(window.location.replace).toHaveBeenCalledWith(
'https://sentry.io/organizations/albertos-apples/issues/?q=123#hash'
);
});
it('redirects to sentryUrl if customer-domains is omitted', function () {
window.__initialData = {
customerDomain: {
subdomain: 'albertos-apples',
organizationUrl: 'https://albertos-apples.sentry.io',
sentryUrl: 'https://sentry.io',
},
features: [],
links: {
organizationUrl: null,
regionUrl: null,
sentryUrl: 'https://sentry.io',
},
} as any;
const organization = OrganizationFixture({
slug: 'albertos-apples',
features: [],
});
const params = {
orgId: 'albertos-apples',
};
const {router, route, routerContext} = initializeOrg({
organization,
router: {
params,
},
});
const WrappedComponent = withDomainRequired(MyComponent);
const {container} = render(
<WrappedComponent
router={router}
location={router.location}
params={params}
routes={router.routes}
routeParams={router.params}
route={route}
/>,
{context: routerContext}
);
expect(container).toBeEmptyDOMElement();
expect(window.location.replace).toHaveBeenCalledTimes(1);
expect(window.location.replace).toHaveBeenCalledWith(
'https://sentry.io/organizations/albertos-apples/issues/?q=123#hash'
);
});
it('renders when window.__initialData.customerDomain and customer-domains feature is present', function () {
window.__initialData = {
customerDomain: {
subdomain: 'albertos-apples',
organizationUrl: 'https://albertos-apples.sentry.io',
sentryUrl: 'https://sentry.io',
},
features: ['organizations:customer-domains'],
links: {
organizationUrl: 'https://albertos-apples.sentry.io',
regionUrl: 'https://eu.sentry.io',
sentryUrl: 'https://sentry.io',
},
} as any;
const organization = OrganizationFixture({
slug: 'albertos-apples',
features: [],
});
const params = {
orgId: 'albertos-apples',
};
const {router, route, routerContext} = initializeOrg({
organization,
router: {
params,
},
});
const WrappedComponent = withDomainRequired(MyComponent);
render(
<WrappedComponent
router={router}
location={router.location}
params={params}
routes={router.routes}
routeParams={router.params}
route={route}
/>,
{context: routerContext}
);
expect(screen.getByText('Org slug: albertos-apples')).toBeInTheDocument();
expect(window.location.replace).toHaveBeenCalledTimes(0);
});
});