Hai @cpojer ,
Ini sebenarnya lebih merupakan masalah jsdom@8
... lihat tmpvar/jsdom#1388, tapi saya ingin menyematkan di sini juga jadi Jest mengambil solusi apa pun yang diberikan jsdom.
Sebelumnya dengan [email protected]/[email protected]
Anda dapat menulis tes seperti ini:
jest.autoMockOff()
jest.setMock('../lib/window', window)
jest.mock('cookies-js')
jest.mock('query-string')
jest.mock('superagent')
describe(['@utils/auth - When an AJAX response returns:'
].join('')
, function () {
beforeEach(function () {
window.location.href = 'http://quux.default.com'
var queryString = require('query-string')
queryString.__setMockParseReturns([{
'access_token': '1234foo',
'expires_in': '9999'
}])
})
it(['should set a redirect token and goto platform ',
'when the AJAX request returns 401.'
].join('')
, function () {
var superagent = require('superagent')
superagent.__setMockAjaxResponses([
[null, { 'status': 401 }]
])
var href = window.location.href
var auth = require('../index.js')
auth.login(function (res) {})
var Cookies = require('cookies-js')
var config = require.requireActual('../config')
expect(decodeURIComponent(window.location.href)).toBe([
config.loginUrl,
config.loginServiceLogin,
'?client_id=',
config.clientId,
'&response_type=token',
'&redirect_uri=',
config.clientRedirectUri
].join(''))
expect(Cookies.__getMockCookieData()[config.clientId + '_state_locationAfterLogin']).toBe(escape(href))
})
Dan ujian itu akan berlalu. Sejak jsdom@8
ini tidak mungkin lagi dan tes ini gagal.
Sepertinya jsdom sedang melihat beberapa jenis kemampuan, hanya ingin memastikan bahwa Jest akan mengambil kemampuan itu ketika tersedia.
Anda benar, ini memang masalah jsdom. Di Facebook, apa yang telah kami lakukan untuk mengatasinya, adalah menggunakan ini:
Object.defineProperty(window.location, 'href', {
writable: true,
value: 'some url'
});
ini berfungsi untuk kami, namun kami masih menggunakan jsdom 7 secara internal.
Saya akan menutup ini, karena saya percaya cara Object.defineProperty
dalam melakukan sesuatu baik-baik saja. Jika itu tidak berhasil untuk Anda di jsdom 8, saya senang untuk membukanya kembali.
Keren, terima kasih saya akan mencoba ini.
@cpojer , sepertinya saya tidak tahu apa yang perlu saya klik untuk membuka kembali masalah ini ...
Apakah ada di lingkungan jest
yang dapat dipanggil jsdom.changeUrl(window, url)
seperti yang dijelaskan di sini https://github.com/tmpvar/jsdom#changing -the-url-of-an-existing-jsdom- jendela-instance di [email protected]
?
tiket lama tetapi bagi mereka yang masih mengalami masalah ini, kami telah mulai menggunakan window.location.assign()
sebagai gantinya sehingga dalam pengujian kami, kami dapat mengejek fungsi assign
seperti itu..
it('will redirect with a bad route', () => {
window.location.assign = jest.fn();
const redirection = shallow(<Redirection />, {
context: {
router: {
location: {
pathname: '/wubbalubbadubdub',
},
},
},
});
expect(window.location.assign).toBeCalledWith(`${CONFIG.APP_LEGACY_ROOT}`);
});
Terima kasih @th3fallen . Itu keren!
Btw @cpojer saya mulai di FB pada 1 Mei.... ;P
Bagus!
Saya mencoba memigrasi pengujian kami dari Mocha+Chai+Sinon.js ke Jest dan tidak dapat menemukan cara mengubah lokasi untuk pengujian tertentu.
Jest 19.x menggunakan JSDom 9.12 yang tidak memungkinkan untuk mengubah lokasi menggunakan trik Object.defineProperty
. Juga, saya tidak dapat menggunakan jsdom.changeURL()
karena alasan yang dijelaskan di tmpvar/jsdom#1700.
@cpojer bagaimana dengan menerapkan beberapa metode proxy ke jsdom.changeURL()
di Jest?
@okovpashko kami berencana untuk mengekspos jsdom ke lingkungan: https://github.com/facebook/jest/issues/2460
Object.defineProperty
bekerja untuk kami di FB.
@thymikee Saya melihat masalah itu tetapi berpikir bahwa proposisi itu ditolak.
@cpojer Saya salah membaca contoh Anda dan mencampurnya dengan yang lain terkait dengan masalah ini, di mana orang menyarankan untuk menggunakan Object.defineProperty(window, 'location', {value: 'url'});
. Terima kasih!
Saya perlu mengubah tidak hanya href, jadi saya menulis metode sederhana, yang mungkin berguna bagi seseorang yang akan membaca utas ini:
const setURL = (url) => {
const parser = document.createElement('a');
parser.href = url;
['href', 'protocol', 'host', 'hostname', 'origin', 'port', 'pathname', 'search', 'hash'].forEach(prop => {
Object.defineProperty(window.location, prop, {
value: parser[prop],
writable: true,
});
});
};
Maaf karena menyeret utas ini lebih jauh, tetapi saya telah mencoba mengejek fungsi Push seperti yang disarankan ...
reactRouterReduxMock.push = (url) => {
Object.defineProperty(window.location, 'href', {
writable: true,
value: url
})
})
tapi saya masih mendapatkan kesalahan jsdom yang sepertinya tidak bisa saya selesaikan:
TypeError: Cannot read property '_location' of null
at Window.location (/Users/user/projects/app/client/node_modules/jsdom/lib/jsdom/browser/Window.js:148:79)
at value (/Users/user/projects/app/client/test/integration-tests/initialSetup.js:122:32) //this is the defineProperty line above
Saya menyadari ini adalah kesalahan jsdom, tetapi bagi mereka yang telah memecahkan ini, apakah ada lagi konteks pengaturan yang dapat Anda bagikan yang mungkin membuat saya menyelesaikan ini?
Terima kasih
@matt-dalton coba saran saya di https://github.com/facebook/jest/issues/890#issuecomment -295939071 berfungsi dengan baik untuk saya
@matt-dalton apa URL Anda? apakah Anda memiliki testURL yang disetel di jest-config.json
Anda atau apakah itu diinisialisasi sebagai about:blank
?
@ianlyons Ya saya menetapkan nilai "https://test.com/"
untuk ini di package.json, dan tidak ada jalur yang muncul sebagai blank
.
@ th3fallen Jika saya memahami Anda dengan benar, saya rasa ini tidak berfungsi untuk kasus penggunaan saya. Apakah Anda meneruskan url sebagai nilai konteks yang menyebabkan penetapan dipicu? Saya mencoba menyusun tes integrasi yang belum sempurna, jadi saya ingin memeriksa bagaimana router merespons beban data awal. Saya telah mengolok-olok respons API, dan kemudian membutuhkan perubahan URL untuk dilakukan menggunakan logika aplikasi (yaitu saya sendiri tidak ingin memicunya secara eksternal).
Object.defineProperty
tampaknya melakukan trik untuk menguji fungsionalitas yang bergantung pada window.location.search
, misalnya. Dikatakan bahwa itu bermutasi window.location.search
sehingga tes lain mungkin terpengaruh. Apakah ada cara untuk "membatalkan" perubahan yang Anda buat pada window.location.search
melalui Object.defineProperty
, seperti fungsi lelucon yang memiliki fungsi mockReset
?
@msholty-fd Anda dapat mencoba pendekatan ini:
const origLocation = document.location.href;
let location = origLocation;
beforeAll(() => {
const parser = document.createElement('a');
['href', 'protocol', 'host', 'hostname', 'origin', 'port', 'pathname', 'search', 'hash'].forEach(prop => {
Object.defineProperty(window.location, prop, {
get: function() {
parser.href = location;
return parser[prop];
}
});
});
});
afterEach(() => {
location = origLocation;
});
test('location 1', () => {
location = "https://www.google.com/";
console.log(document.location.href); // https://www.google.com/
});
test('location 2', () => {
console.log(document.location.href); // about:blank
});
Itu berhenti bekerja di Jest 22.0.1
Object.defineProperty(window.location, 'href', {
writable: true,
value: 'some url'
});
Pesan eror:
TypeError: Cannot redefine property: href
at Function.defineProperty (<anonymous>)
Hmm, entah bagaimana kita mungkin perlu mengizinkan orang untuk menelepon reconfigure
. https://github.com/tmpvar/jsdom/blob/05a6deb6b91b4e02c53ce240116146e59f7e14d7/README.md#reconfiguring -the-jsdom-with-reconfiguresettings
Membuka masalah baru yang terkait dengan ini, karena yang ini sudah ditutup: #5124
@SimenB Saya tidak yakin bahwa Jest harus memperbaiki ini. JSDOM harus mengizinkan window.location.assign()
untuk bekerja sebagaimana dimaksud dan mengkonfigurasi ulang output dari window.location.href
dll.
Saya mendapat TypeError: Could not parse "/upgrades/userlogin?hardwareSku=sku1351000490stgvha" as a URL
karena jsdom memiliki url dasar default ke about:blank
Saya mencoba menetapkan url dasar ke jsdom
, menghabiskan 4 jam tanpa berhasil (saya tahu cara melakukannya, cukup masukkan <base href='your_base_url' />
ke dom; tetapi , dom dibuat oleh jest
, bukan oleh saya, jadi saya menyerah.
solusi Object.defineProperty
hanya berfungsi dengan versi lama jsdom
(Anda mendapatkan 'tidak dapat mendefinisikan ulang kesalahan properti dengan versi jsdom
yang lebih baru);
jika Anda menggunakan jsdom
ver > 10, seperti yang disebutkan @th3fallen adalah solusi yang tepat.
gunakan window.location.assign
adalah cara yang tepat
Jika Anda hanya menginginkan url selain about:blank
, Anda dapat menggunakan konfigurasi testURL
.
terima kasih @SimenB atas balasan Anda.
Tidak, saya berbicara tentang base url
bukan url
. Saya memiliki kode yang akan melakukan window.location.href="/login"
dan ketika menjalankan jest
, jsdom
membuang pengecualian mengeluh /login
bukan url yang valid
TypeError: Could not parse "/login" as a URL
Saya memeriksa kode sumber jsdom
dan menyadari ini karena saya tidak memiliki pengaturan url dasar (ini setara dengan mengetik "/ login" di bilah URL browser tanpa alamat dasar).
dengan jsdom
, biasanya kita dapat mengatur url dasar melalui
global.jsdom = new JSDOM('<html><head> <base href="base_url" /></head></html>')
tetapi karena jest
mengatur jsdom
, itu di luar kendali kami.
--- pembaruan: Saya kira saya dapat secara eksplisit menambahkan jsdom
sebagai ketergantungan dan mengkonfigurasi jsdom
secara manual.
Saya kemudian menemukan solusi yaitu mengganti window.location.href=
dengan window.location.assign
dan mengejek fungsi assign
dan itu berhasil untuk saya
@bochen2014 masalah ini memiliki informasi lebih lanjut tentang cara menggunakan versi jsdom yang lebih baru: #5124
tl;dr: Anda dapat mengejek window.location.assign()
, atau Anda dapat menggunakan jest-environment-jsdom-global
, yang memungkinkan Anda mengonfigurasi ulang jsdom dalam penerbangan.
terima kasih @simon360
itulah yang saya lakukan ;-)
Saya menggunakan jsdom.reconfigure
untuk menyiapkan urls
awal yang berbeda dalam pengujian saya, dan setiap kali saya perlu mengubah url dalam kode (bukan pengujian), saya menggunakan window.location.assign
dan mengejeknya. yang bekerja untuk saya.
hanya untuk orang-orang yang mungkin/akan mengalami masalah yang sama, untuk mengatur url untuk jsdom Anda
// jest.config.js
module.exorts={
testURL: 'http://localhost:3000',
// or :
testEnvironmentOptions: {
url: "http://localhost:3000/",
referrer: "https://example.com/",
}
}
perhatikan bahwa ini akan mengatur url untuk semua pengujian Anda;
jika Anda menginginkan url yang berbeda dalam beberapa pengujian tertentu, gunakan jsdom.reconfigure
api;
jika Anda perlu mengubah url dengan cepat di luar kode unit test (yaitu kode produksi), Anda perlu menggunakan window.location.assign
dan mengejeknya.
Diposting di tiket lain, tapi saya posting di sini:
Menemukan solusi yang bagus untuk Jest 21.2.1
Ok, sejauh ini solusi termudah untuk mengatasi ini adalah:
Masuk ke pengaturan Jest Anda (misalnya saya akan menggunakan package.json):
"jest": {
"testURL": "http://localhost"
}
Sekarang Anda akan memiliki akses ke objek jendela dan kemudian Anda dapat mengatur URL ke apa pun yang Anda suka selama pengujian.
it('Should set href url to testURL', () => {
// Here I set href to my needs, opinionated stuff bellow
const newUrl = 'http://localhost/editor.html/content/raiweb/it/news/2018/02/altered-carbon-best-cyberpunk-tv-series-ever.html';
Object.defineProperty(window.location, 'href', {
writable: true,
value: newUrl
});
console.log(window.location.href);
});
it('Should set pathname url to testURL', () => {
// Here I set href to my needs, opinionated stuff bellow
const newUrl = '/editor.html/content/raiweb/it/news/2018/02/altered-carbon-best-cyberpunk-tv-series-ever.html';
Object.defineProperty(window.location, 'pathname', {
writable: true,
value: newUrl
});
console.log(window.location.pathname);
});
Semoga ini bisa membantu seseorang.
@petar-prog91 yang sangat membantu. Anda memiliki kesalahan ketik - seharusnya testURL
bukan TestURL
@BarthesSimpson terima kasih atas pemberitahuannya, komentar yang diperbarui.
Berhenti memposting ini, ini tidak berfungsi pada lelucon": "^22.4.2"
Hai,
Saya telah menggunakan ini dalam pengujian, saya menghapus status global dan membuat yang baru dengan jsdom... :
describe('componentDidMount', () => {
delete global.window
const window = (new JSDOM(``, {url: 'https://example.org/'})).window
global.window = window
describe('When window is defined', () => {
const spy = jest.spyOn(Utils, 'extractTokenFromUrl')
it('should call extract token function with window location', () => {
mount(<Header />)
expect(spy).toHaveBeenCalledWith('https://example.org/')
})
})
})
@UserNT konfirmasi — itu memberikan TypeError: Cannot redefine property: href
@annemarie35 tidak berfungsi — ReferenceError: JSDOM is not defined
Saya tidak tahu apakah ini akan membantu seseorang, tetapi inilah yang saya lakukan saat ini.
const redirectTo = (url: string): void => {
if (process.env.NODE_ENV === "test") {
global.jsdom.reconfigure({ url: `${getBaseUrl()}${url}` });
} else {
window.location.replace(url);
}
};
Tulis fungsi redirect dan gunakan itu sebagai gantinya. Jadi dalam pengujian env, itu akan bergantung pada url jsdom.reconfigure untuk mengubah bagian url.
Saya menggunakannya seperti ini
export const clientFetchData = (
history: Object,
routes: Object,
store: Object
) => {
const callback = location =>
match({ routes, location }, (error, redirectLocation, renderProps) => {
if (error) {
redirectTo("/500.html");
} else if (redirectLocation) {
redirectTo(redirectLocation.pathname + redirectLocation.search);
} else if (renderProps) {
if (!isEmpty(window.prerenderData)) {
// Delete initial data so that subsequent data fetches can occur
window.prerenderData = undefined;
} else {
// Fetch mandatory data dependencies for 2nd route change onwards
trigger(
FETCH_DATA_HOOK,
renderProps.components,
getDefaultParams(store, renderProps)
);
}
trigger(
UPDATE_HEADER_HOOK,
renderProps.components,
getDefaultParams(store, renderProps)
);
} else {
redirectTo("/404.html");
}
});
history.listen(callback);
callback(history.getCurrentLocation());
};
Setelah itu, dalam pengujian Anda, bisa seperti ini
describe("# match route", () => {
it("should navigate to error page", () => {
fetchData.clientFetchData(history, components, store);
reactRouter.match.mock.calls[0][1](true);
expect(window.location.href).toEqual(`${SERVER_URL}/500.html`);
});
it("should redirect to /hello-world.html page", () => {
fetchData.clientFetchData(history, components, store);
reactRouter.match.mock.calls[0][1](undefined, {
pathname: "/hello-world.html",
search: ""
});
expect(window.location.href).toEqual(`${SERVER_URL}/hello-world.html`);
});
...
Saya akhirnya melakukan ini yang berhasil:
global.window = new jsdom.JSDOM('', {
url: 'http://www.test.com/test?foo=1&bar=2&fizz=3'
}).window;
Saya memiliki ini di bagian atas file pengaturan JSDOM saya:
const { JSDOM } = require('jsdom');
const jsdom = new JSDOM('<!doctype html><html><body><div id="root"></div></body></html>', {
url: "http://test.com"
});
const { window } = jsdom;
function copyProps(src, target) {
const props = Object.getOwnPropertyNames(src)
.filter(prop => typeof target[prop] === 'undefined')
.map(prop => Object.getOwnPropertyDescriptor(src, prop));
Object.defineProperties(target, props);
}
global.document = window.document;
global.window = window;
global.navigator = {
userAgent: 'node.js',
};
global.HTMLElement = window.HTMLElement;
Memperbaikinya dengan mengatur "testURL": " http://localhost/ " di Jest config (Saya menggunakan versi terbaru). Secara default " about:blank " dan itu menyebabkan kesalahan JSDOM (Anda tidak dapat mengubah url "about:blank" ke yang lain).
Sumber daya:
http://jestjs.io/docs/en/configuration#testurl -string
https://github.com/jsdom/jsdom/issues/1372
Saya menemukan posting ini sangat membantu: https://www.ryandoll.com/post/2018/3/29/jest-and-url-mocking
"Dalam konfigurasi Jest Anda, pastikan untuk mengatur yang berikut:
"testURL": "https://www.somthing.com/test.html"
Kemudian di bagian beforeEach() Anda untuk pengujian Anda, ubah jalur sesuai kebutuhan dengan menggunakan
sejarah.pushState().
window.history.pushState({}, 'Test Title', '/test.html?query=true');
Voila! Sekarang Anda mengubah jalur Anda untuk pengujian apa pun, tanpa harus mengganti konfigurasi jsdom apa pun seperti yang disarankan orang lain di utas yang disebutkan di atas. Tidak yakin di utas mana saya menemukan solusi ini, tetapi pujian untuk dev yang mempostingnya!"
@Mike-Tran Anda keren! Itu benar-benar berhasil, sangat sederhana. Saya bahkan tidak perlu menggunakan pengaturan testURL.
@Mike-Tran Itu berhasil! Terimakasih! Namun, saya tidak membutuhkan testURL
atau beforeEach
. Saya baru saja melakukannya:
window.history.pushState({}, 'Test Title', '/test.html?query=true');
Dan sekarang saya tidak perlu menggunakan Object.defineProperty
lagi
@jcmcneal terima kasih yang melakukannya untuk saya! (bercanda 23.0.0)
Jika tujuan Anda adalah untuk mengejek objek window
, inilah solusi saya (tidak begitu elegan, tetapi berhasil):
Buat kelas antarmuka (tidak yakin apakah antarmuka adalah kata yang tepat, tapi saya harap Anda mengerti maksudnya):
// window.js
export const { location } = window;
Dalam kode Anda yang sebenarnya, tukar window
dengan metode antarmuka, misalnya win
// myFile.js
import * as win from './window';
export function doSomethingThatRedirectsPage() {
win.location.href = 'google.com';
}
Kemudian, dalam tes lelucon Anda, Anda hanya mengejeknya sehingga jsdom tidak mengeluh. Anda bahkan dapat menegaskannya:
// myFile.test.js
import * as myFile from './myFile';
import * as win from './window';
it('should redirect', () => {
win.location = { href: 'original-url' };
expect(win.location.href).toBe('original-url');
myFile.doSomethingThatRedirectsPage();
expect(win.location.href).toBe('google.com');
});
@Mike-Tran , @jcmcneal terima kasih! Semua bekerja sebagai aspek!
class SSOtestComponent memperluas React.Component {
componentDidMount() {
let isSuccess = this.props.location.pathname === '/sso/test/success' ? true : false
window.opener.postMessage({ type: "sso_test", isSuccess,...this.props.location.query}, window.location.origin)
}
onSsoAuthenticate() {
}
componentWillUnmount() {
}
render() {
return (<Loader />);
}
}
module.exports = SSOtestComponent;
saya menulis unit test case menggunakan enjyme dan bercanda bagaimana menulis kondisi window.location ... tolong beri jawabannya
ini berhasil untuk saya
const location = JSON.stringify(window.location);
delete window.location;
Object.defineProperty(window, 'location', {
value: JSON.parse(location)
});
Object.defineProperty(global.location, 'href', {
value: 'http://localhost/newURL',
configurable: true
});
pada versi lelucon 23.6.0
Ini berhasil untuk saya.
delete global.window.location
global.window.location = { href: 'https://test-domain.com.br', ...anyOptions }
@FelipeBohnertPaetzold terima kasih
Terima kasih @FelipeBohnertPaetzold. Saya menggunakan location.host
dalam kode saya, jadi ternyata saya membutuhkan objek lokasi lengkap , jadi yang berikut ini berfungsi lebih baik untuk saya, daripada harus secara manual melewati setiap properti lokasi:
delete global.window.location;
global.window.location = new URL("https://www.ediblecode.com/");
Catatan, ini berfungsi di Node 6.13+ (lihat URL class docs ) dan saya menggunakan Jest 24.
Perhatikan juga, ini tidak berfungsi dengan URL relatif, lihat https://url.spec.whatwg.org/#example -url-parsing.
TypeScript ini berfungsi untuk saya di Jest 24.0.0 dan Node 10.15.0 :
import { mockWindow } from './testUtils';
mockWindow(window, 'http://localhost');
describe('setup tests', () => {
describe('window.location', () => {
const saveLocation = window.location;
afterAll(() => {
delete window.location;
window.location = saveLocation;
});
it('location.assign assigns a location', () => {
window.location.assign('http://foo.com');
expect(window.location.href).toBe('http://foo.com/');
(window.location.assign as jest.Mock<void, [string]>).mockClear();
});
it('location.replace replaces a location', () => {
window.location.replace('http://bar.com');
expect(window.location.href).toBe('http://bar.com/');
(window.location.replace as jest.Mock<void, [string]>).mockClear();
});
it('location.reload is a spy', () => {
window.location.reload();
expect(window.location.reload).toHaveBeenCalledTimes(1);
(window.location.reload as jest.Mock).mockClear();
});
});
});
interface MockedLocation extends Location {
assign: jest.Mock<void, [string]>;
reload: jest.Mock;
replace: jest.Mock<void, [string]>;
}
interface MockedWindow extends Window {
location: MockedLocation;
}
export function mockWindow(win: Window = window, href = win.location.href) {
const locationMocks: Partial<MockedLocation> = {
assign: jest.fn().mockImplementation(replaceLocation),
reload: jest.fn(),
replace: jest.fn().mockImplementation(replaceLocation),
};
return replaceLocation(href);
function replaceLocation(url: string) {
delete win.location;
// tslint:disable-next-line:no-any
win.location = Object.assign(new URL(url), locationMocks) as any;
return win as MockedWindow;
}
}
import { mockWindow } from './testUtils';
describe('test utils', () => {
describe('mockWindow', () => {
const saveLocation = window.location;
afterAll(() => {
delete window.location;
window.location = saveLocation;
});
it('location.assign assigns a location', () => {
const { assign } = mockWindow().location;
assign('http://foo.com');
expect(window.location.href).toBe('http://foo.com/');
assign.mockClear();
});
it('location.replace replaces a location', () => {
const { replace } = mockWindow().location;
replace('http://bar.com');
expect(window.location.href).toBe('http://bar.com/');
replace.mockClear();
});
it('location.reload is a spy', () => {
const { reload } = mockWindow().location;
reload();
expect(window.location.reload).toHaveBeenCalledTimes(1);
reload.mockClear();
});
});
});
@jedmao
Hei, man) Utilitas yang bagus!
Bagi saya pengujian di src/setupTests.test.ts
sedikit berlebihan, karena Anda sudah sepenuhnya menguji util mockWindow
di src/testUtils.test.ts. Jadi, dalam pengujian untuk src/setupTests.ts
sudah cukup untuk menguji, bahwa Anda memanggil mockWindow
dengan argumen yang benar.
Terima kasih)
@tzvipm @jup-iter terima kasih atas 👍. Saya baru saja merilis @jedmao/storage
dan @jedmao/location
, yang keduanya sepenuhnya agnostik dari Jest. Anda seharusnya dapat spyOn
metode yang sesuai tanpa menulis tes tambahan apa pun, karena paket npm telah diuji sepenuhnya.
Jika Anda mendapatkan kesalahan ini saat menggunakan Vue, cukup gunakan this.$router.push({...})
daripada this.$router.go({...})
Tempatkan kode di bawah ini pada baris 1:
delete global.window.location;
global.window.location = "";
Peristiwa klik yang mengubah window.location sekarang dapat ditangkap.
"bercanda": "^23.6.0"
Ini bekerja:
delete window.location;
window.location = Object.assign({}, window.location);
const url = Object.assign({}, new URL('http://google.com'));
Object.keys(url).forEach(prop => (window.location[prop] = url[prop]));
Atau lebih baik lagi...
delete (global as any).window;
(global as any).window = new JSDOM(undefined, { url: 'http://google.com' }).window;
Anda benar, ini memang masalah jsdom. Di Facebook, apa yang telah kami lakukan untuk mengatasinya, adalah menggunakan ini:
Object.defineProperty(window.location, 'href', { writable: true, value: 'some url' });
ini berfungsi untuk kami, namun kami masih menggunakan jsdom 7 secara internal.
Saya akan menutup ini, karena saya percaya cara
Object.defineProperty
dalam melakukan sesuatu baik-baik saja. Jika itu tidak berhasil untuk Anda di jsdom 8, saya senang untuk membukanya kembali.
Ya, saya memiliki beberapa fungsi yang berurusan dengan location.search
dan location.hash
, dan saya ingin mengujinya dengan defineProperty
seperti yang Anda sebutkan. Ini tidak akan berhasil!
Ketika saya mematikan mode diam jest
, saya menemukan ini: Error: Not implemented: navigation (except hash changes)
console.error node_modules/jsdom/lib/jsdom/virtual-console.js:29
Error: Not implemented: navigation (except hash changes)
at module.exports (/home/ghlandy/projects/wdph-utils/node_modules/jsdom/lib/jsdom/browser/not-implemented.js:9:17)
at navigateFetch (/home/ghlandy/projects/wdph-utils/node_modules/jsdom/lib/jsdom/living/window/navigation.js:74:3)
at exports.navigate (/home/ghlandy/projects/wdph-utils/node_modules/jsdom/lib/jsdom/living/window/navigation.js:52:3)
at LocationImpl._locationObjectNavigate (/home/ghlandy/projects/wdph-utils/node_modules/jsdom/lib/jsdom/living/window/Location-impl.js:29:5)
at LocationImpl.assign (/home/ghlandy/projects/wdph-utils/node_modules/jsdom/lib/jsdom/living/window/Location-impl.js:213:10)
at Location.assign (/home/ghlandy/projects/wdph-utils/node_modules/jsdom/lib/jsdom/living/generated/Location.js:93:25)
at Object.assign (/home/ghlandy/projects/wdph-utils/src/__tests__/url.test.js:6:14)
at Object.asyncJestLifecycle (/home/ghlandy/projects/wdph-utils/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:53:37)
at resolve (/home/ghlandy/projects/wdph-utils/node_modules/jest-jasmine2/build/queueRunner.js:43:12)
at new Promise (<anonymous>) undefined
Dan sekarang saya tidak tahu bagaimana cara menguji fungsi saya.
Adakah yang punya cara untuk mengubah tes url
Anda benar, ini memang masalah jsdom. Di Facebook, apa yang telah kami lakukan untuk mengatasinya, adalah menggunakan ini:
Object.defineProperty(window.location, 'href', { writable: true, value: 'some url' });
ini berfungsi untuk kami, namun kami masih menggunakan jsdom 7 secara internal.
Saya akan menutup ini, karena saya percaya caraObject.defineProperty
dalam melakukan sesuatu baik-baik saja. Jika itu tidak berhasil untuk Anda di jsdom 8, saya senang untuk membukanya kembali.Ya, saya memiliki beberapa fungsi yang berurusan dengan
location.search
danlocation.hash
, dan saya ingin mengujinya dengandefineProperty
seperti yang Anda sebutkan. Ini tidak akan berhasil!Ketika saya mematikan mode diam
jest
, saya menemukan ini:Error: Not implemented: navigation (except hash changes)
console.error node_modules/jsdom/lib/jsdom/virtual-console.js:29 Error: Not implemented: navigation (except hash changes) at module.exports (/home/ghlandy/projects/wdph-utils/node_modules/jsdom/lib/jsdom/browser/not-implemented.js:9:17) at navigateFetch (/home/ghlandy/projects/wdph-utils/node_modules/jsdom/lib/jsdom/living/window/navigation.js:74:3) at exports.navigate (/home/ghlandy/projects/wdph-utils/node_modules/jsdom/lib/jsdom/living/window/navigation.js:52:3) at LocationImpl._locationObjectNavigate (/home/ghlandy/projects/wdph-utils/node_modules/jsdom/lib/jsdom/living/window/Location-impl.js:29:5) at LocationImpl.assign (/home/ghlandy/projects/wdph-utils/node_modules/jsdom/lib/jsdom/living/window/Location-impl.js:213:10) at Location.assign (/home/ghlandy/projects/wdph-utils/node_modules/jsdom/lib/jsdom/living/generated/Location.js:93:25) at Object.assign (/home/ghlandy/projects/wdph-utils/src/__tests__/url.test.js:6:14) at Object.asyncJestLifecycle (/home/ghlandy/projects/wdph-utils/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:53:37) at resolve (/home/ghlandy/projects/wdph-utils/node_modules/jest-jasmine2/build/queueRunner.js:43:12) at new Promise (<anonymous>) undefined
Dan sekarang saya tidak tahu bagaimana cara menguji fungsi saya.
Adakah yang punya cara untuk mengubah tes
url
Dan dalam situasi saya, memiliki bidang testURL
dalam file jest.config.js
dapat berfungsi. Tetapi bagaimana jika saya ingin mengubah testURL sebelum setiap pengujian.
Saya menemukan posting ini sangat membantu: https://www.ryandoll.com/post/2018/3/29/jest-and-url-mocking
"Dalam konfigurasi Jest Anda, pastikan untuk mengatur yang berikut:
"testURL": "https://www.somthing.com/test.html"
Kemudian di bagian beforeEach() Anda untuk pengujian Anda, ubah jalur sesuai kebutuhan dengan menggunakan
sejarah.pushState().window.history.pushState({}, 'Test Title', '/test.html?query=true');
Voila! Sekarang Anda mengubah jalur Anda untuk pengujian apa pun, tanpa harus mengganti konfigurasi jsdom apa pun seperti yang disarankan orang lain di utas yang disebutkan di atas. Tidak yakin di utas mana saya menemukan solusi ini, tetapi pujian untuk dev yang mempostingnya!"
Solusi luar biasa!!! Terima kasih banyak! @Mike-Tran
Saya menginginkan solusi singkat dan tidak invasif seperti ini!
Agar ini berfungsi pada Juni 2019 saya harus melakukan ini:
delete global.window.location;
global.window = Object.create(window);
global.window.location = {
port: '123',
protocol: 'http:',
hostname: 'localhost',
};
saya pakai ini....
window.history.pushState({}, '', `${url}/`);
Mungkin bagian dari JSDOMTestWrapper saya dapat membantu seseorang
/** <strong i="6">@type</strong> {Window} */
this.testWindowObject = Object.create(window);
const wnd = this.testWindowObject;
this.testWindowObject.history = {
state: null,
prev: { /** <strong i="7">@todo</strong> immutable stack with the go(step) method emulation */
state: null,
pathname: null,
search: null,
},
go(step) {
logger.special('history go called', step);
logger.warn('history go has not supported yet');
},
back() {
this.state = this.prev.state;
wnd.location.pathname = this.prev.pathname;
wnd.location.search = this.prev.search;
const eventData = this.state ? { url: this.state.displayURL, newState: this.state, type: 'push' } : null;
wnd.sm.eventsService.triggerEvent(ROUTER_EVENTS.ROUTE_PUSH, eventData);
wnd.sm.urlService.simpleRouteTo(`${ wnd.location.pathname || '' }${ wnd.location.search || '' }`);
logger.special('history back emulated');
},
pushState(state, title, url) {
this.prev.state = Object.assign({}, this.state);
this.prev.pathname = '' + wnd.location.pathname;
this.prev.search = '' + wnd.location.search;
this.state = state;
if (title) wnd.document.title = title;
const [p, s] = url.split('?');
wnd.location.pathname = p;
wnd.location.search = s ? `?${ s }` : '';
logger.special('push state emulated', { state, title, url });
},
replaceState(state, title, url) {
this.prev.state = Object.assign({}, this.state);
this.prev.pathname = '' + wnd.location.pathname;
this.prev.search = '' + wnd.location.search;
this.state = state;
if (title) wnd.document.title = title;
const [p, s] = url.split('?');
wnd.location.pathname = p;
wnd.location.search = s ? `?${ s }` : '';
logger.special('replace state emulated', { state, title, url });
logger.special('test: urlService.getPathName()', wnd.sm.urlService.getPathName());
},
};
this.testWindowObject.innerWidth = WND_WIDTH;
this.testWindowObject.innerHeight = WND_HEIGHT;
this.testWindowObject.fetch = fetchFn;
this.testWindowObject.localStorage = lstMock;
this.testWindowObject.scrollTo = (x, y) => {
/** not implemented yet https://github.com/jsdom/jsdom/issues/1422 */
if (typeof x !== 'number' && (x.left || x.top)) {
y = x.top;
x = x.left;
}
// logger.info(`window.scrollTo(${ x }, ${ y })`);
};
if (fetchFn === JSDOMTestWrapper.FETCH_FN.DEV_MOCK) {
global.Request = RequestMock;
this.testWindowObject.Request = RequestMock;
}
if (href) {
this.testWindowObject.location = Object.assign({}, this.testWindowObject.location, urlapi.parse(href));
}
else {
this.testWindowObject.location = Object.assign({}, this.testWindowObject.location);
}
(function(ELEMENT) {
ELEMENT.matches = ELEMENT.matches || ELEMENT.mozMatchesSelector || ELEMENT.msMatchesSelector || ELEMENT.oMatchesSelector || ELEMENT.webkitMatchesSelector;
ELEMENT.closest = ELEMENT.closest || function closest(selector) {
if (!this) return null;
if (this.matches(selector)) return this;
if (!this.parentElement) {return null}
else return this.parentElement.closest(selector)
};
ELEMENT.getBoundingClientRect = ELEMENT.getBoundingClientRect || (() =>
({ bottom: WND_HEIGHT, height: WND_HEIGHT, left: 0, right: WND_WIDTH, top: 0, width: WND_WIDTH, x: 0, y: 0 }));
}(Element.prototype));
this.testWindowObject.getBoundingClientRect = () =>
({ bottom: WND_HEIGHT, height: WND_HEIGHT, left: 0, right: WND_WIDTH, top: 0, width: WND_WIDTH, x: 0, y: 0 });
this.testWindowObject.__resizeListeners__ = [];
this.testWindowObject.__resizeTriggers__ = {};
this.testWindowObject._detectElementResize = {
removeResizeListener: () => {},
};
this.testWindowObject.matchMedia = jest.fn().mockImplementation(query => {
return {
matches: false,
media: query,
onchange: null,
addListener: jest.fn(),
removeListener: jest.fn(),
};
});
this.rftpr = () => {};
this.mode = mode;
this.renderFirstTimePromise = new Promise((resolve) => {
this.rftpr = resolve;
});
this.marpr = () => {};
this.mobileAppReadyPromise = new Promise((resolve) => {
this.marpr = resolve;
});
if (mode === JSDOMTestWrapper.MODE.MOBILE_APP) {
this.testWindowObject.navigator = Object.assign({}, this.testWindowObject.navigator, {
language: storeKey,
appVersion: '5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Mobile Safari/537.36',
userAgent: 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Mobile Safari/537.36',
vendor: 'Google Inc.',
});
global.intercom = {
registerUnidentifiedUser: jest.fn(),
registerForPush: jest.fn(),
};
}
const XApp = mode ? MobileApp : App;
const app = <XApp window={ this.testWindowObject } rftResolve={ this.rftpr } storeKey={ storeKey } apiHost={ apiVersion } forceMobileDetection={ mode } />;
render(app, this.testWindowObject.document.body);
if (mode === JSDOMTestWrapper.MODE.MOBILE_APP) {
setTimeout(() => {
this.testWindowObject.sm.deviceService.appRestorePathHasInit = this.marpr;
this.testWindowObject.sm.deviceService.fireEvent(this.testWindowObject.document, 'deviceready');
}, 200);
}
Pendekatan ini berfungsi pada 27 Sep 2019: https://stackoverflow.com/a/54034379/1344144
global.window = Object.create(window);
const url = "http://dummy.com";
Object.defineProperty(window, "location", {
value: {
href: url
},
writable: true
});
Solusi lain bekerja untuk saya saat ini tanpa menulis jsdom
:
testURL
di jest.config.js
berapa pun nilainya:// jest.config.js
'testURL': 'https://someurl.com'
Dalam file pengujian Anda:
window.history.pushState({}, 'Mocked page title', 'www.yoururl.com');
Dipetik dari: https://www.ryandoll.com/post/2018/3/29/jest-and-url-mocking. Terima kasih untuk Ryan!
tidak bekerja untuk saya:
TypeError: Penetapan ke properti hanya-baca tidak diizinkan dalam mode ketat
it("should save hash when history is not found", () => {
const historyBkp = global.window.history;
delete global.window.history;
global.window.history = false;
externalLoader.savePageURL(urlTraining);
expect(window.location.hash).to.be.equal(`#page=${urlTraining}`);
global.window.history = historyBkp;
window.location.hash = "";
});
tidak bekerja untuk saya:
TypeError: Penetapan ke properti hanya-baca tidak diizinkan dalam mode ketat
it("should save hash when history is not found", () => { const historyBkp = global.window.history; delete global.window.history; global.window.history = false; externalLoader.savePageURL(urlTraining); expect(window.location.hash).to.be.equal(`#page=${urlTraining}`); global.window.history = historyBkp; window.location.hash = ""; });
tambahkan ini ke file global.
hapus global.window.location;
global.window.location = "";
Pendekatan ini berfungsi pada 27 Sep 2019: https://stackoverflow.com/a/54034379/1344144
global.window = Object.create(window); const url = "http://dummy.com"; Object.defineProperty(window, "location", { value: { href: url }, writable: true });
Saya mencoba sesuatu yang serupa, dengan location.assign, tetapi sepertinya ini tidak berfungsi lagi.
ini bekerja untuk saya di lelucon 24.9.0
window.history.replaceState({}, 'Test Title', '/test?userName=James&userNumber=007');
ini bekerja untuk saya di lelucon 24.9.0
window.history.replaceState({}, 'Test Title', '/test?userName=James&userNumber=007');
Saya harus membuat kode async agar ini berfungsi karena saya menjalankan kode di dalam janji.
jadi bekerja sekarang
Bagaimana cara menguji lokasi chenge di tindakan vuex?
async setForm({ rootState, state, commit, dispatch }, formData) {
....
switch (answ.result.type) {
....
case 'redirect':
console.log(answ.data.url);
window.location = answ.data.url;
console.log({ location: window.location.href });
break;
default:
break;
it('setForm - success, redirect', async done => {
expect(window.location.href).toBe('https://www.google.ru/');
Saya memiliki kesalahan:
expect(received).toBe(expected) // Object.is equality
Expected: "https://www.google.ru/"
Received: "http://localhost/"
ini berhasil untuk saya
const location = JSON.stringify(window.location); delete window.location; Object.defineProperty(window, 'location', { value: JSON.parse(location) }); Object.defineProperty(global.location, 'href', { value: 'http://localhost/newURL', configurable: true });
pada versi lelucon 23.6.0
apa globalnya?
di mana definisi globalnya?
Ini berhasil untuk saya.
delete global.window.location global.window.location = { href: 'https://test-domain.com.br', ...anyOptions }
ini membuat Lokasi dengan semua fungsi asli, tetapi dapat diolok-olok:
beforeAll(() => {
const location = window.location
delete global.window.location
global.window.location = Object.assign({}, location)
})
Komentar yang paling membantu
Anda benar, ini memang masalah jsdom. Di Facebook, apa yang telah kami lakukan untuk mengatasinya, adalah menggunakan ini:
ini berfungsi untuk kami, namun kami masih menggunakan jsdom 7 secara internal.
Saya akan menutup ini, karena saya percaya cara
Object.defineProperty
dalam melakukan sesuatu baik-baik saja. Jika itu tidak berhasil untuk Anda di jsdom 8, saya senang untuk membukanya kembali.