Error in mounted hook: "Reference Error: local Storage is not defined"솔루션
이번에 겪은 문제는 테스트 페이지(즉
.vue
파일)에서 Vue Test Utils의 mount/shallow Mount 방법을 사용하여 페이지를 만들었다는 것이다.페이지에서localStorage를 사용하여 일부 사용자 데이터를 액세스하기 때문에, 페이지는 시종 마운트할 수 없고, 오류가 발생했습니다. Error in mounted hook: "ReferenceError: localStorage is not defined
솔직히 화면이 온통 빨갛게 달아오르는 것을 보면 짜증이 난다. 그러나 이 오보도 정상이다. 이론적으로 페이지에 호출된local Storage는window.localStorage
이고 단원 테스트는 분명히 노드 환경에서 실행되고 노드 환경에는 윈도라는 전역 변수가 없다(대신 글로벌, 내가 앞서 언급한 바와 같이), 자연도 없다window.localStorage
.vue-cli에 통합된 단원 테스트 플러그인@vue/cli-plugin-unit-mocha
의 문서에서도 이 점을 명확하게 지적했다.vue-cli-service test:unit
Run unit tests with mocha-webpack + chai.
Note the tests are run inside Node.js with browser environment simulated with JSDOM.
그러나 이곳의 환경은 조금 다르다. 전혀 없다
window
고 해도 옳지 않은 것 같다. 왜냐하면 여기에 JSDOM도 도입되었기 때문이다.JSDOM 이 패키지는 노드 환경에서 브라우저 환경을 모의하는 데 사용됩니다. window
구체적인 사용 세부 사항은 스스로 문서를 조회할 수 있지만, 여기에 윈도우가 있다는 것만 명확히 하면 된다.이론적으로, 우리는 윈도우에 local Storage를 추가하기만 하면 문제를 해결할 수 있다.먼저 설명하자면 다음은 모두 JS에 기초한 토론이다. 왜냐하면 이 라이브러리의 실현은 모두 JS이기 때문이다.그래서 일반적인 사고방식은 반드시 이와 같은 실현이다.
window.localStorage = {
data: {},
setItem(key, value) {
this.data[key] = value;
},
getItem(key) {
return this.data[key];
}
};
// TypeError: Cannot set property localStorage of # which has only a getter
이런 작법은 비엄격한 모드에서는 침묵에 실패하고 엄격한 모드에서는 틀릴 수 있다.이것도 매우 재미있는 일이다. 왜냐하면 이곳의
window.localStorage
는 Getter만 있고 값을 부여할 수 없기 때문이다.그러니 우회해야 한다.나중에 시험에서 나는 해결 방안을 얻었다. 먼저
dom-storage
이라는 가방을 도입했고 dom-storage
는 사실local Storage 기능을 실현했고 파일 읽기와 쓰기 기능을 제공했다.그리고 js 파일을 만듭니다. 예를 들어 localStorage.js
라고 부르십시오.// localStorage.js
const Storage = require('dom-storage');
global.localStorage = new Storage(null, {strict: true});
window.localStorage = global.localStorage;
그리고 단원 테스트에 이 파일을 도입합니다.문제 해결.
기쁜 나머지 이 코드를 자세히 생각해 보면 수상한 점을 발견할 수 있다.
window.localStorage
값을 부여할 수 없지 않습니까?코드를 바꾸자 바로 같은 오류가 발생했다.// localStorage.js
'use strict';
const Storage = require('dom-storage');
global.localStorage = new Storage(null, {strict: true});
window.localStorage = global.localStorage;
// TypeError: Cannot set property localStorage of # which has only a getter
결론도 간단하다. 단원 테스트를 할 때 테스트 논리 호출은
global.localStorage
이어야 한다.이 점을 검증하기 위해 페이지에console를 추가합니다.log, 출력은 다음과 같습니다.// Test.vue
mounted() {
console.log(localStorage);
}
// localStorage.js
const Storage = require('dom-storage');
global.localStorage = new Storage(null, {strict: true});
window.localStorage = global.localStorage;
window.localStorage.setItem('test', 'test');
console.log(window.localStorage);
// Storage { test: 'test' }
// Storage {}
사실은 결국 문서에 있는 그 말로 돌아왔다.
Note the tests are run inside Node.js with browser environment simulated with JSDOM.
Node 환경에서 실행되는 한 글로벌과의 상호작용을 피할 수 없다.이렇게 한 바퀴 돌았는데 주로 JSDOM이 사람들에게 가져온 오해가 너무 깊어서 사람들이 노드에 윈도우를 만들었고 글로벌을 대체할 수 있다고 생각하게 한다.실은 그렇지 않다.
마지막으로 이 서류는 JS로 쓰는 것이 비교적 편리하다.TS는 온갖 방법을 다 동원하여 우리의 수정
global
을 방해할 것이기 때문에 이 작은 문제를 해결하기 위해 자체적으로 확장할 것이다.d.ts는 얻는 것보다 잃는 것이 많은 것 같다.TS에 JS를 섞는 건 좋지 않지만 문제를 해결할 수 있으니 이런 디테일을 신경 쓸 필요가 없다.물론 굳이 쓰지 않아도 안 되는 것은 아니지만, 먼저 원래의 인터페이스를 확장해야 한다.
// shims-node.d.ts
declare namespace NodeJS {
interface Global {
localStorage: any
}
}
// localStorage.ts
global.localStorage = {
data: {},
getItem(key: string) {
return this.data[key];
},
setItem(key: string, value: string) {
this.data[key] = value;
}
};
끝.
이번에 단원 테스트를 쓰기 위해 이상한 버그가 많아지자 이를 보고도 좀 무감각해진 것 같은데...
모두가 알다시피 vue-cli3은 vue-cli2보다 훨씬 낫다. 더욱 간소화된 프로젝트 구조, 더욱 빠른 구축 속도, 고도의 추상적인 프로필, 더 많은 부합도가 높은 플러그인, 더욱 매끄러운 오픈 체험은 모두 사람을 편안하게 한다.좋은 점도 말하고 나쁜 점도 말한다. vue-cli3의 간결함은 사실 양날의 검으로 편리함과 동시에 버그를 숨기는 문제를 발견하기 어렵다.참으로 괴롭다.
그 전에 나는 또 다른 몇 가지 방안을 시험해 보았지만 모두 실패로 끝났고, 각종 이상한 문제가 발생했다.그중 가장 이상한 것은 사용
mock-local-storage
할 때 나온 것이다.이 패키지를 도입한 후(vue-cli3에서 프로젝트를 만들 때 단원 테스트를 선택하면 자체@vue/cli-plugin-unit-mocha
;이 가방에는 jsdom-global
이 도입되어 vue-cli-service test:unit --require jsdom-global --require mock-local-storage
호출을 통해 오류가 발생하고local Storage를 찾을 수 없습니다.vue-cli-service test:unit --require jsdom-global mock-local-storage
로 바꾸면 다음과 같이 됩니다.WEBPACK Compiled successfully in xxxxms
MOCHA Testing...
0 passing (0ms)
MOCHA Tests completed successfully
테스트는 통과된 것 같았지만 실제로는 전혀 진행되지 않았다.호출 창고를 따라 추적해 내려가면 프로젝트 루트 디렉터리
/node_modules/@vue/cli-plugin-unit-mocha/index.js
의 60번째 줄(다른 프로젝트/시스템/IDE에 편차가 있을 수 있지만 이 줄 근처)에서 문제가 발견되고 이 줄hasInlineFilesGlob
에는true가 부여되어 후속 테스트 논리가 바로 건너뜁니다.명령--require
뒤에 모듈을 초과할 때 이 논리를 촉발할 수 있기 때문이다.그런데 왜 이러는지 모르겠다.주로 경험이 얕아서 웹 패키지에 대해 잘 몰라요.따라서 일단 문제를 기록한 다음에 천천히 탐색하자.만약 아는 사람이 있다면 아낌없이 가르침을 주십시오.