Как запустить скрипт JavaScript через Терминал?
Например, если вы должны запустить Python script, вы должны ввести python filename.py или если вы хотите запустить программу C, введите имя файла, а затем. /filename. Как вы это делаете с файлами .js?
BLUC 16 дек. 2011, в 12:21
Поделиться
Извините, я не знаю C. Каким будет правильный термин для описания файла C?
BLUC 16 дек. 2011, в 10:43
JS не является языком общего назначения, так почему вы хотите это сделать? Включите файл .js в страницу .htm (l) с помощью тега
helpermethod 16 дек. 2011, в 10:44
@BLUC BLUC Это называется исполняемый файл.
helpermethod 16 дек. 2011, в 10:44
исполняемый файл, приложение, программа или двоичный файл. И на более полезной заметке вам понадобится интерпретатор JavaScript, такой как V8 или Rhino, или один из 1000 других, которые я забыл.
Corbin 16 дек. 2011, в 10:45
@OliverWeiler не так легко применим в общих ситуациях, как некоторые другие языки, но я верю, что его приложения могут быть вне веб-страниц :).
Corbin 16 дек. 2011, в 10:46
@Oliver Так как я новичок в JS, мне просто проще сделать это, но если это невозможно, я сделаю это. Спасибо!
BLUC 16 дек. 2011, в 10:46
Приложение JavaScript в Unity 3D
Bradman175 05 март 2017, в 13:00
Показать ещё 5 комментариев
Поделиться:
13 ответов
Лучший ответ
Для оценки script вам понадобится механизм JavaScript (например, Mozilla Rhino), как и для Python, хотя последний поставляется со стандартным распределением.
Если у вас установлен Rhino (или альтернатива) и на вашем пути, то запуск JS действительно может быть таким же простым, как
> rhino filename.js
Следует отметить, что хотя JavaScript — это просто собственный язык, многие конкретные сценарии предполагают, что они будут выполняться в среде, подобной браузерам, и поэтому пытайтесь получить доступ к глобальным переменным, таким как location.href , и создавать выходные данные путем добавления объектов DOM, а не вызова print .
Если у вас есть script, который был написан для веб-страницы, вам может потребоваться его несколько обернуть или изменить, чтобы он мог принимать аргументы из stdin и писать в stdout. (Я считаю, что у Rhino есть режим для эмуляции стандартных глобальных браузеров, которые помогают много, хотя я не могу найти документы для этого сейчас.)
Как запустить файл js в node js
Для работы с файлами в Node.js предназначен модуль fs. Рассмотрим, как с ним работать.
Чтение из файла
Допустим, в одной папке с файлом приложения app.js расположен текстовый файл hello.txt с простейшим текстом, например:
Hello Node JS!
Для чтения файла в синхронном варианте применяется функция fs.readFileSync() :
let fileContent = fs.readFileSync("hello.txt", "utf8");
В метод передается путь к файлу относительно файла приложения app.js, а в качестве второго параметра указывается кодировка для получения текстового содержимого файла. На выходе получаем считанный текст.
Для асинхронного чтения файла применяется функция fs.readFile :
fs.readFile("hello.txt", "utf8", function(error,data)< >);
Первый и второй параметр функции опять же соответственно путь к файлу и кодировка. А в качестве третьего параметра передается функция обратного вызова, которая выполняется после завершения чтения. Первый параметр этой функции хранит информацию об ошибке при наличии, а второй — собственно считанные данные.
Для чтения файла определим в файле app.js следующий код:
const fs = require("fs"); // асинхронное чтение fs.readFile("hello.txt", "utf8", function(error,data)< console.log("Асинхронное чтение файла"); if(error) throw error; // если возникла ошибка console.log(data); // выводим считанные данные >); // синхронное чтение console.log("Синхронное чтение файла") let fileContent = fs.readFileSync("hello.txt", "utf8"); console.log(fileContent);
И здесь стоит обратить внимание, что несмотря на то, что функция fs.readFile() вызывается первой, но так как она асинхронная, она не блокирует поток выполнения, поэтому ее результат выводится в самом конце.
Запись файла
Для записи файла в синхронном варианте используется функция fs.writeFileSync() , которая в качестве параметра принимает путь к файлу и записываемые данные:
fs.writeFileSync("hello.txt", "Привет ми ми ми!")
Также для записи файла можно использовать асинхронную функцию fs.writeFile() , которая принимает те же параметры:
fs.writeFile("hello.txt", "Привет МИГ-29!")
В качестве вспомогательного параметра в функцию может передаваться функция обратного вызова, которая выполняется после завершения записи:
const fs = require("fs"); fs.writeFile("hello.txt", "Hello мир!", function(error)< if(error) throw error; // если возникла ошибка console.log("Асинхронная запись файла завершена. Содержимое файла:"); let data = fs.readFileSync("hello.txt", "utf8"); console.log(data); // выводим считанные данные >);

Следует отметить, что эти методы полностью перезаписывают файл. Если надо дозаписать файл, то применяются методы fs.appendFile()/fs.appendFileSync() :
const fs = require("fs"); fs.appendFileSync("hello.txt", "Привет ми ми ми!"); fs.appendFile("hello.txt", "Привет МИД!", function(error)< if(error) throw error; // если возникла ошибка console.log("Запись файла завершена. Содержимое файла:"); let data = fs.readFileSync("hello.txt", "utf8"); console.log(data); // выводим считанные данные >);

Удаление файла
Для удаления файла в синхронном варианте используется функция fs.unlinkSync() , которая в качестве параметра принимает путь к удаляемому файлу:
fs.unlinkSync("hello.txt")
Также для удаления файла можно использовать асинхронную функцию fs.unlink() , которая принимает путь к файлу и функцию, вызываемую при завершении удаления:
fs.unlink("hello.txt", (err) => < if (err) console.log(err); // если возникла ошибка else console.log("hello.txt was deleted"); >);
Тестирование модуля Node.js с использованием Mocha и Assert

Тестирование является неотъемлемой частью разработки программного обеспечения. Обычно программисты запускают код, который тестирует разработанные ими приложения, при внесении каких-либо изменений, чтобы убедиться, что все работает, как надо. При правильных тестовых настройках этот процесс можно автоматизировать, что значительно позволит сэкономить время. Запуск тестов непосредственно после написания нового кода гарантирует сохранность ранее существовавших функций. Таким образом разработчик может быть уверенным в базе кода, особенно когда она внедряется в производственную среду, чтобы пользователи могли взаимодействовать с ней.
Мы создаем примеры тестирования с помощью структур тестовых фреймворков. Mocha — это популярный тестовый фреймворк JavaScript, используемый для организации и запуска тестовых файлов. Однако Mocha не подтверждает поведение нашего кода. Для сравнения значений в тесте мы можем использовать модуль Node.js assert .
В этой статье вы узнаете, как написать тесты для списка дел (TODO) для модуля Node.js. Для создания тестов будет настроен и использован фреймворк Mocha. Также будет использован модуль Node.js assert для создания самих тестов. В этом смысле вы будете использовать Mocha в качестве планировщика, а assert для реализации плана.
Предварительные требования
- Node.js, установленный на вашем компьютере для разработки. В этом обучающем руководстве используется версия Node.js 10.16.0. Чтобы установить его в macOS или Ubuntu 18.04, следуйте указаниям руководства Установка Node.js и создание локальной среды разработки в macOS или раздела Установка с помощью PPA руководства Установка Node.js в Ubuntu 18.04.
- Базовые знания JavaScript, которые можно получить из нашей серии статей Программирование на JavaScript.
Шаг 1 — Создание модуля Node
Давайте начнем с написания модуля Node.js, который мы будем тестировать. Этот модуль будет управлять списком элементов TODO. Используя этот модуль, мы сможем перечислить все элементы списка TODO, которые нужно отследить, добавить новые элементы и отметить некоторые как выполненные. Также мы сможем экспортировать список элементов TODO в файл CSV. Если вам нужно вспомнить, как писать модули Node.js, прочтите нашу статью Создание модуля Node.js.
Для начала необходимо настроить среду программирования. Создайте папку с именем проекта в своем терминале. В данном обучающем руководстве будет использоваться имя todos :
Затем откройте эту папку:
Теперь инициализируйте npm, поскольку позже мы будем использовать его функцию командной строки для запуска тестирования:
У нас есть только одна зависимость, Mocha, которую мы будем использовать для организации и запуска тестов. Для загрузки и установки Mocha воспользуйтесь следующей командой:
Мы установим Mocha как зависимость dev , поскольку это не требуется модулем в производственных настройках. Если вы хотите узнать больше о пакетах Node.js или npm, ознакомьтесь с руководством Использование модулей Node.js с npm и package.json.
Наконец, создадим файл, который будет содержать код нашего модуля:
Теперь мы готовы создать наш модуль. Откройте index.js в текстовом редакторе, например nano :
Давайте начнем с определения класса Todos . Этот класс содержит все функции, необходимые для управления нашим списком TODO. Добавьте следующие строки кода в index.js :
todos/index.js
class Todos constructor() this.todos = []; > > module.exports = Todos;
Начнем с создания класса Todos . Его функция constructor() не принимает аргументов, поэтому нам не нужно предоставлять значения для создания объекта для данного класса. Все, что мы делаем, когда инициализируем объект Todos , — это создаем свойство todos , которое является пустым массивом.
Линия модулей позволяет другим модулям Node.js требовать наш класс Todos . Без прямого экспорта класса тестовый файл, который мы создадим позже, не сможет использовать его.
Давайте добавим функцию для возврата сохраненного массива todos . Запишите следующие выделенные строки:
todos/index.js
class Todos < constructor() < this.todos = []; >list() return [. this.todos]; > > module.exports = Todos;
Функция list() возвращает копию массива, используемого классом. Она делает копию массива, используя деструктурирующий синтаксис JavaScript. Мы создаем копию массива, чтобы изменения, которые пользователь вносит в массив, возвращенный функцией list() , не влияли на массив, используемый объектом Todos .
Примечание. Массивы JavaScript — это справочные файлы. Это значит, что для любого присваивания переменной для массива или вызова функции с массивом в качестве параметра JavaScript обращается к оригинальному созданному массиву. Например, если у нас есть массив с тремя элементами с именем x и мы создаем новую переменную y , так что y = x , y и x относятся к одному и тому же. Все изменения, выполняемые для массива с y , влияют на переменную x и наоборот.
Теперь создадим функцию add() , которая добавляет новый элемент TODO:
todos/index.js
class Todos < constructor() < this.todos = []; >list() < return [. this.todos]; >add(title) let todo = title: title, completed: false, > this.todos.push(todo); > > module.exports = Todos;
Наша функция add() берет строку и помещает ее в свойство title нового объекта JavaScript. Новый объект также имеет свойство completed , которое по умолчанию устанавливается на false . Затем мы добавляем этот новый объект к нашему массиву TODO.
Важной функцией в менеджере TODO является отметка элементов как завершенные. Для выполнения этой задачи мы пройдем в цикле по нашему массиву todos , чтобы найти элемент TODO, который ищет пользователь. Если элемент найден, отметим его как завершенный. Если ничего не найдено, выдадим ошибку.
Добавьте функцию complete() следующим образом:
todos/index.js
class Todos < constructor() < this.todos = []; >list() < return [. this.todos]; >add(title) < let todo = < title: title, completed: false, >this.todos.push(todo); > complete(title) let todoFound = false; this.todos.forEach((todo) => if (todo.title === title) todo.completed = true; todoFound = true; return; > >); if (!todoFound) throw new Error(`No TODO was found with the title: "$"`); > > > module.exports = Todos;
Сохраните файл и выйдите из текстового редактора.
Теперь у нас есть базовый менеджер TODO, с которым можно экспериментировать. Далее проверим код вручную, чтобы убедиться в работе приложения.
Шаг 2 — Ручное тестирование кода
В этом шаге мы запустим функции нашего кода и посмотрим на вывод, чтобы убедиться, что он соответствует ожиданиям. Это называется тестированием вручную. Оно выполняется аналогично наиболее распространенным методам тестирования, используемым программистами. Хотя позже мы автоматизируем тестирование с помощью Mocha, сначала протестируем наш код вручную, чтобы иметь лучшее представление о том, как тестирование вручную отличается от тестовых фреймворков.
Добавим в наше приложение два элемента TODO и отметим один из них как завершенный. Запустите Node.js REPL в той же папке, что и файл index.js :
Вы увидите командную строку > в REPL, которая указывает, что мы можем ввести код JavaScript. Введите в командную строку следующее:
С помощью require() мы загружаем модуль TODO в переменную Todos . Помните, что наш модуль возвращает класс Todos по умолчанию.
Теперь инстанцируем объект для этого класса. В REPL добавьте следующую строку кода:
Мы можем использовать объект todos для проверки работы реализации. Добавим первый элемент TODO:
До сих пор мы не видели никаких выводов в нашем терминале. Давайте убедимся, что мы сохранили элемент TODO run code , получив список всех наших TODO:
Вы увидите следующий вывод в вашем REPL:
Output[ < title: 'run code', completed: false >]
Это ожидаемый результат: у нас есть один элемент TODO в нашем массиве TODO, и он не завершен по умолчанию.
Добавим другой элемент TODO:
Отметим первый элемент TODO как завершенный:
Теперь наш объект todos будет управлять двумя элементами: run code и test everything . TODO run code также будет завершен. Подтвердим это, вызвав list() еще раз:
Вывод REPL будет выглядеть следующим образом:
Output[ < title: 'run code', completed: true >, < title: 'test everything', completed: false >]
Теперь закройте REPL следующим образом:
Мы подтвердили, что наш модуль работает соответствующим образом. Хотя мы не поместили наш код в тестовый файл и не использовали тестовую библиотеку, мы вручную протестировали код. К сожалению, эта форма тестирования займет много времени, если ее использовать при выполнении каждого изменения. Далее попробуем выполнить автоматизированное тестирование в Node.js и посмотрим, возможно ли решить данную проблему с помощью тестового фреймворка Mocha.
Шаг 3 — Создание первого теста с помощью Mocha и Assert
В последнем шаге мы вручную протестировали наше приложение. Это будет работать в отдельных случаях, но по мере масштабирования модуля этот метод станет менее целесообразным. Поскольку тестируются новые функции, необходимо убедиться, что добавленная функциональность не создала проблем в предыдущем варианте. Мы хотели бы протестировать каждую функцию еще раз для каждого изменения в коде, но выполнение этой задачи вручную потребует огромных усилий и увеличит вероятность возникновения ошибок.
Гораздо эффективнее настроить автоматическое тестирование. Тестирование по сценарию создается аналогично другим блокам кода. Мы запускаем наши функции с определенными вводами и проверяем их действие, чтобы убедиться, что они работают соответствующим образом. По мере роста базы кода мы будем автоматизировать тестирование. Когда мы прописываем тесты наряду с функциями, то можем проверить работоспособность всего модуля без необходимости каждый раз запоминать, как использовать ту или иную функцию.
В этом обучающем руководстве мы используем тестовый фреймворк Mocha с модулем Node.js assert . Давайте на практике посмотрим, как они вместе работают.
Для начала создадим новый файл для хранения кода теста:
Теперь с помощью предпочтительного текстового редактора откройте файл тестирования. Можно использовать nano , как раньше:
В первой строке текстового файла мы загрузим модуль TODO аналогично тому, как мы делали в оболочке Node.js. Затем мы загрузим модуль assert , чтобы он был на момент создания тестов. Добавьте следующие строки:
todos/index.test.js
const Todos = require('./index'); const assert = require('assert').strict;
Свойство strict модуля assert позволит нам использовать специальные тесты эквивалентности, рекомендуемые Node.js, которые также подходят для проверок в дальнейшем, поскольку отвечают за большее число вариантов использования.
Прежде чем приступить к написанию тестов, давайте обсудим, как Mocha организует наш код. Тестирование с использованием Mocha, как правило, использует следующие шаблоны:
describe([String with Test Group Name], function() < it([String with Test Name], function() < [Test Code] >); >);
Обратите внимание на две ключевые функции: describe() и it() . Функция describe() используется для группировки аналогичных тестов. Для Mocha не требуется запускать тесты, но их группировка упростит поддержку нашего кода теста. Рекомендуется группировать тесты таким образом, чтобы было проще обновлять аналогичные вместе.
it() содержит наш код теста. Именно здесь мы могли бы взаимодействовать с функциями нашего модуля и использовать библиотеку assert . Многие функции it() могут быть определены в функции describe() .
Цель этого раздела состоит в использовании Mocha и assert для автоматизации нашего ручного теста. Мы будем делать это постепенно, начав с блока описания. Добавьте в файл следующее после строк модуля:
todos/index.test.js
. describe("integration test", function() >);
С помощью этого блока кода мы создали группировку для наших объединенных тестов. Тесты блока проверяют по одной функции за раз. Интеграционные тесты проверяют, насколько хорошо функции в модулях или между ними работают вместе. Когда Mocha запускает наш тест, все тесты в этом блоке описания будут запущены в группе интеграционных тестов .
Давайте добавим функцию it() , чтобы начать тестирование нашего кода модуля:
todos/index.test.js
. describe("integration test", function() < it("should be able to add and complete TODOs", function() >); >);
Обратите внимание, каким наглядным мы сделали название теста. Для всех, кто запустит наш тест, станет сразу понятно, что пройдено, а что — нет. Хорошо протестированное приложение — это, как правило, хорошо задокументированное приложение, и тесты иногда могут быть эффективным способом документирования.
Для нашего первого теста мы создадим новый объект Todos и проверим, что в нем нет элементов:
todos/index.test.js
. describe("integration test", function() < it("should be able to add and complete TODOs", function() < let todos = new Todos(); assert.notStrictEqual(todos.list().length, 1); >); >);
Первая новая строка кода инстанциировала новый объект Todos , как мы делали в Node.js REPL или другом модуле. Во второй новой строке мы использовали модуль assert .
Из модуля assert мы используем метод notStrictEqual() . Эта функция учитывает два параметра: значение, которое необходимо протестировать (называется фактическое значение), и значение, которое мы ожидаем получить (называется ожидаемое значение). Если эти оба аргумента одинаковы, notStrictEqual() выдает ошибку о непрохождении теста.
Сохраните и закройте index.test.js .
Базовый сценарий будет истинным, так как длина должна быть 0 , что не равно 1 . Давайте убедимся в этом, запустив Mocha. Для этого нам потребуется модифицировать наш файл package.json . Откройте файл package.json в своем текстовом редакторе:
Теперь в свойстве scripts измените его следующим образом:
todos/package.json
. "scripts": "test": "mocha index.test.js" >, .
Мы только что изменили поведение команды test командной строки npm. Когда мы запустим npm test , npm проверит команду, которую мы только что ввели в package.json . Он будет искать библиотеку Mocha в нашей папке node_modules и запустит команду mocha с нашим файлом тестирования.
Сохраните и закройте package.json .
Давайте посмотрим, что происходит, когда мы запускаем наш тест. В своем терминале введите:
Команда выдаст следующий вывод:
Output> todos@1.0.0 test your_file_path/todos > mocha index.test.js integrated test ✓ should be able to add and complete TODOs 1 passing (16ms)
Этот вывод сначала покажет нам, какая группа тестов сейчас запустится. Для каждого отдельного теста в группе тестовый сценарий является ступенчатым. Мы видим наше имя теста так, как мы описали его в функции it() . Галочка с левой стороны тестового сценария указывает на то, что тест пройден.
Внизу мы получим резюме всех наших тестов. В нашем случае один тест был выполнен и завершен в течение 16 мс (время зависит от компьютера).
Тестирование началось успешно. Однако текущий тестовый сценарий может допускать ложные позитивные результаты. Ложные позитивные результаты — это тестовый сценарий, когда тест пройден тогда, когда не должен.
Теперь мы проверяем, что длина массива не равна 1 . Давайте изменим тест, чтобы это условие было истинным, когда не должно. Добавьте следующие строки в index.test.js :
todos/index.test.js
. describe("integration test", function() < it("should be able to add and complete TODOs", function() < let todos = new Todos(); todos.add("get up from bed"); todos.add("make up bed"); assert.notStrictEqual(todos.list().length, 1); >); >);
Сохраните и закройте файл.
Мы добавили два элемента TODO. Давайте запустим тест, чтобы увидеть, что произойдет:
В результате вы получите следующий вывод:
Output. integrated test ✓ should be able to add and complete TODOs 1 passing (8ms)
Он проходит согласно ожиданиям, так как длина больше 1. Однако он не достигает первоначальной цели проведения этого первого теста. Первый тест должен был подтвердить, что мы начинаем с чистого состояния. Более совершенный тест подтвердит это во всех случаях.
Давайте изменим тест таким образом, что его успешное прохождение будет возможным только при полном отсутствии TODO в памяти. Выполните следующие изменения в index.test.js :
todos/index.test.js
. describe("integration test", function() < it("should be able to add and complete TODOs", function() < let todos = new Todos(); todos.add("get up from bed"); todos.add("make up bed"); assert.strictEqual(todos.list().length, 0); >); >);
Вы изменили notStrictEqual() на strictEqual() , функцию, которая проверяет эквивалентность между фактическим и ожидаемым аргументом. Строгое равенство (Strict equal) завершится неудачей, если наши аргументы не полностью одинаковы.
Сохраните и закройте файл, затем запустите тест, чтобы увидеть, что произойдет:
В этот раз вывод покажет ошибку:
Output. integration test 1) should be able to add and complete TODOs 0 passing (16ms) 1 failing 1) integration test should be able to add and complete TODOs: AssertionError [ERR_ASSERTION]: Input A expected to strictly equal input B: + expected - actual - 2 + 0 + expected - actual -2 +0 at Context. (index.test.js:9:10) npm ERR! Test failed. See above for more details.
Этот текст пригодится только для отладки причины непрохождения теста. Обратите внимание, что поскольку тест не был пройден, в начале тестового сценария не было галочки.
Резюме теста находится уже не внизу вывода, а сразу после нашего списка отображенных тестовых сценариев:
. 0 passing (29ms) 1 failing .
В остальной части вывода предоставлены данные о непройденных тестах. Сначала мы видим, какие тестовые сценарии не пройдены:
. 1) integrated test should be able to add and complete TODOs: .
Затем мы увидим причину непрохождения теста:
. AssertionError [ERR_ASSERTION]: Input A expected to strictly equal input B: + expected - actual - 2 + 0 + expected - actual -2 +0 at Context. (index.test.js:9:10) .
Выдается AssertionError , когда не выполняется strictEqual() . Мы видим, что ожидаемое значение 0 отличается от фактического значения 2.
Затем мы увидим строку в нашем файле тестирования, где код не выполняется. В этом случае это строка 10.
Теперь мы воочию убедились, что наш тест не будет пройден, если мы будем ожидать некорректные результаты. Давайте изменим наш тестовый сценарий обратно на правильное значение. Откройте файл:
Затем выберите строки todos.add , чтобы ваш код выглядел следующим образом:
todos/index.test.js
. describe("integration test", function () it("should be able to add and complete TODOs", function () let todos = new Todos(); assert.strictEqual(todos.list().length, 0); >); >);
Сохраните и закройте файл.
Запустите его еще раз, чтобы убедиться в прохождении без каких-либо ложных позитивных результатов:
Вывод будет выглядеть следующим образом:
Output. integration test ✓ should be able to add and complete TODOs 1 passing (15ms)
Теперь мы значительно улучшили отказоустойчивость нашего теста. Давайте перейдем к нашему интеграционному тесту. Следующий шаг — добавить новый элемент TODO в index.test.js :
todos/index.test.js
. describe("integration test", function() < it("should be able to add and complete TODOs", function() < let todos = new Todos(); assert.strictEqual(todos.list().length, 0); todos.add("run code"); assert.strictEqual(todos.list().length, 1); assert.deepStrictEqual(todos.list(), []); >); >);
После использования функции add() мы подтверждаем, что у нас есть один элемент TODO, управляемый нашим объектом todos , при этом мы будем использовать strictEqual() . Наш следующий тест подтверждает данные в todos с помощью deepStrictEqual() . Функция deepStrictEqual() рекурсивно проверяет, имеют ли наши предполагаемые и реальные объекты одни и те же свойства. В этом случае проверяется, содержат ли оба ожидаемых массива объект JavaScript. Затем проверяется, имеют ли эти объекты JavaScript одинаковые свойства, т. е. оба их свойства title — это run code , а оба свойства completed — false .
Затем выполним оставшиеся тесты, используя эти два теста равенства, добавив следующие выделенные строки:
todos/index.test.js
. describe("integration test", function() < it("should be able to add and complete TODOs", function() < let todos = new Todos(); assert.strictEqual(todos.list().length, 0); todos.add("run code"); assert.strictEqual(todos.list().length, 1); assert.deepStrictEqual(todos.list(), []); todos.add("test everything"); assert.strictEqual(todos.list().length, 2); assert.deepStrictEqual(todos.list(), [ < title: "run code", completed: false >, ] ); todos.complete("run code"); assert.deepStrictEqual(todos.list(), [ < title: "run code", completed: true >, ] ); >); >);
Сохраните и закройте файл.
Теперь наш тест имитирует ручной тест. Благодаря этим программируемым тестам исчезает необходимость постоянной проверки выводов, если запускать тесты для контроля соответствия критериям. Обычно вы стараетесь проверить каждый шаг, чтобы убедиться в корректности тестирования кода.
Давайте еще раз запустим тест npm test для получения данного вывода:
Output. integrated test ✓ should be able to add and complete TODOs 1 passing (9ms)
Вы настроили комплексный тест с помощью Mocha и библиотеки assert .
Рассмотрим ситуацию, когда мы разделили наш модуль с другими разработчиками, и теперь они предоставляют нам обратную связь. Большинство пользователей хотели бы, чтобы функция complete() возвращала ошибку, в случае если ни один элемент TODO еще не добавлен. Добавим это свойство в функцию complete() .
Откройте index.js в редакторе:
Добавьте в функцию следующее:
todos/index.js
. complete(title) if (this.todos.length === 0) throw new Error("You have no TODOs stored. Why don't you add one first?"); > let todoFound = false this.todos.forEach((todo) => if (todo.title === title) todo.completed = true; todoFound = true; return; > >); if (!todoFound) throw new Error(`No TODO was found with the title: "$title>"`); > > .
Сохраните и закройте файл.
Теперь добавим новый тест для этой новой функции. Нам нужно убедиться, что в случае если мы вызываем команду complete объекту Todos , в котором нет элементов, будет возвращена ошибка.
Вернитесь в index.test.js :
В конце файла добавьте следующий код:
todos/index.test.js
. describe("complete()", function() it("should fail if there are no TODOs", function() let todos = new Todos(); const expectedError = new Error("You have no TODOs stored. Why don't you add one first?"); assert.throws(() => todos.complete("doesn't exist"); >, expectedError); >); >);
Снова используем describe() и it() . Этот тест начинается с создания нового объекта todos . Затем мы определяем ошибку, которую ожидаем получить при вызове функции complete() .
Далее используем функцию throws() модуля assert . Эта функция была создана для проверки ошибок, которые выдаются в коде. Первый аргумент — это функция, содержащая код, который выдает ошибку. Второй аргумент — это ошибка, которую мы ожидаем получить.
Снова запустите тест с помощью npm test в своем терминале и вы увидите следующий вывод:
Output. integrated test ✓ should be able to add and complete TODOs complete() ✓ should fail if there are no TODOs 2 passing (25ms)
Этот вывод подтверждает преимущества автоматизированного тестирования с помощью Mocha и assert . Поскольку наши тесты выполняются скриптами, каждый раз, когда мы запускаем npm test , мы проверяем, что все тесты успешно пройдены. Нам не нужно вручную проверять, работает ли другой код. Мы знаем, что работает, так как наш тест успешно пройден.
Таким образом, с помощью этих тестов мы проверили результаты синхронного кода. Посмотрим, как можно адаптировать эти методы тестирования для работы с асинхронным кодом.
Шаг 4 — Тестирование асинхронного кода
Одна из функций, описанных в нашем модуле TODO, — это функция экспорта CSV. Она выводит все элементы TODO, а также завершенный статус в файл. Для этого требуется использовать модуль fs — встроенный модуль Node.js для работы с файловой системой.
Запись в файл — это асинхронная операция. В Node.js есть много способов записи в файл. Можно использовать обратные вызовы, обещания или ключевые слова async / await . В этом разделе мы рассмотрим, как записывать тесты для разных методов.
Обратные вызовы
Функция callback — это функция, используемая как аргумент для асинхронной функции. Она вызывается при завершении асинхронной операции.
Добавим функцию в наш класс Todos с именем saveToFile() . Эта функция будет создавать строку, проходя циклом через все элементы TODO и записывая эту строку в файл.
Откройте файл index.js :
Добавьте в этот файл следующий выделенный код:
todos/index.js
const fs = require('fs'); class Todos < constructor() < this.todos = []; >list() < return [. this.todos]; >add(title) < let todo = < title: title, completed: false, >this.todos.push(todo); > complete(title) < if (this.todos.length === 0) < throw new Error("You have no TODOs stored. Why don't you add one first?"); >let todoFound = false this.todos.forEach((todo) => < if (todo.title === title) < todo.completed = true; todoFound = true; return; >>); if (!todoFound) < throw new Error(`No TODO was found with the title: "$"`); > > saveToFile(callback) let fileContents = 'Title,Completed\n'; this.todos.forEach((todo) => fileContents += `$,$\n` >); fs.writeFile('todos.csv', fileContents, callback); > > module.exports = Todos;
Сначала необходимо импортировать модуль fs в наш файл. Затем добавляем новую функцию saveToFile() . Эта функция выполняет функцию обратного вызова, которая активируется сразу после завершения операции записи файла. В этой функции мы создаем переменную fileContents , содержащую всю строку, которую мы хотим сохранить в качестве файла. Она активируется с помощью заголовков CSV. Затем проходим циклом через каждый элемент TODO с помощью метода внутреннего массива forEach() . В процессе итерации добавляем свойства title и completed отдельных объектов todos .
Наконец, используем модуль fs для записи файла с помощью функции writeFile() . Первый аргумент — это имя файла: todos.csv . Второй — это содержимое файла, в этом случае fileContents — это переменная. Последний аргумент — это наша функция обратного вызова, которая обрабатывает любые ошибки записи файла.
Сохраните и закройте файл.
Теперь напишем тест для функции saveToFile() . Этот тест выполняет две функции: в первую очередь подтверждает наличие файла, а затем проверяет, имеет ли файл правильное содержимое.
Откройте файл index.test.js :
Начнем с загрузки модуля fs в верхней части файла, так как мы будем использовать его для тестирования результатов:
todos/index.test.js
const Todos = require('./index'); const assert = require('assert').strict; const fs = require('fs'); .
Теперь в конце файла добавим новый тест:
todos/index.test.js
. describe("saveToFile()", function() it("should save a single TODO", function(done) let todos = new Todos(); todos.add("save a CSV"); todos.saveToFile((err) => assert.strictEqual(fs.existsSync('todos.csv'), true); let expectedFileContents = "Title,Completed\nsave a CSV,false\n"; let content = fs.readFileSync("todos.csv").toString(); assert.strictEqual(content, expectedFileContents); done(err); >); >); >);
Как и ранее, используем команду describe() для группировки нашего теста отдельно от других, так как он подразумевает новую функцию. Функция it() несколько отличается от других функций. Обычно у используемой нами функции обратного вызова нет аргументов. В этот раз у нас есть done в качестве аргумента. Этот аргумент требуется при тестировании функций с обратными вызовами. Функция обратного вызова done() используется Mocha для информирования о завершении асинхронной функции.
Все функции обратного вызова, протестированные в Mocha, должны вызывать обратный вызов done() . Если нет, Mocha не будет знать, когда функция была завершена, и зависнет в ожидании сигнала.
Далее создаем экземпляр Todos и добавляем в него один элемент. Затем вызываем функцию saveToFile() с обратным вызовом, который фиксирует ошибку записи файла. Обратите внимание, как тест для этой функции располагается в обратном вызове. Если бы код теста был за пределами обратного вызова, тест бы не прошел, так как код вызывался до завершения записи файла.
В нашей функции обратного вызова мы сначала проверяем наличие нашего файла:
todos/index.test.js
. assert.strictEqual(fs.existsSync('todos.csv'), true); .
Функция fs.existsSync() возвращает true , если путь файла в аргументе существует, и false , если нет.
Примечание. Функции модуля fs — асинхронные по умолчанию. Однако для ключевых функций существуют синхронные копии. Этот тест упрощен с помощью синхронных функций, так как нам не нужно встраивать асинхронный код для проверки работы теста. В модуле fs синхронные функции, как правило, имеют Sync в конце имен.
Затем создаем переменную для хранения ожидаемого значения:
todos/index.test.js
. let expectedFileContents = "Title,Completed\nsave a CSV,false\n"; .
Используем readFileSync() модуля fs для синхронного чтения файла:
todos/index.test.js
. let content = fs.readFileSync("todos.csv").toString(); .
Теперь предоставляем readFileSync() правильный путь для файла: todos.csv . Поскольку readFileSync() возвращает буферный объект Buffer , который хранит бинарные данные, мы используем метод toString() для сравнения его значения со строкой, которую мы предположительно сохранили.
Как и ранее, используем strictEqual модуля assert для выполнения сравнения:
todos/index.test.js
. assert.strictEqual(content, expectedFileContents); .
Заканчиваем тест вызовом обратного вызова done() , чтобы убедиться, что Mocha знает, что нужно остановить тестирование:
todos/index.test.js
. done(err); .
Мы указываем объект err в done() , тогда Mocha не пройдет тест в случае возникновения ошибки.
Сохраните и закройте index.test.js .
Запускаем этот тест с помощью npm test , как и ранее. Вы увидите следующий вывод на консоли:
Output. integrated test ✓ should be able to add and complete TODOs complete() ✓ should fail if there are no TODOs saveToFile() ✓ should save a single TODO 3 passing (15ms)
Вы протестировали первую асинхронную функцию с Mocha, используя функцию обратных вызовов. Но, как описывается в статье Написание асинхронного кода в Node.js, на момент написания этого обучающего руководства обещания используются чаще, чем обратные вызовы в новом коде Node.js. Далее давайте посмотрим, как протестировать их с помощью Mocha.
Обещания
Обещание — это объект JavaScript, который в конечном счете возвращает значение. Когда обещание успешно, оно разрешено. Когда встречается ошибка, оно отклоняется.
Давайте изменим функцию saveToFile() таким образом, чтобы она использовала обещания вместо обратных вызовов. Откройте index.js :
Сначала нам нужно изменить загрузку модуля fs . В вашем файле index.js измените выражение require() в верхней части файла, чтобы это выглядело следующим образом:
todos/index.js
. const fs = require('fs').promises; .
Мы только что импортировали модуль fs , который использует обещания, а не обратные вызовы. Теперь нам нужно внести некоторые изменения в команду saveToFile() , чтобы она работала с обещаниями.
В вашем текстовом редакторе внесите в функцию saveToFile() следующие изменения для удаления обратных вызовов:
todos/index.js
. saveToFile() let fileContents = 'Title,Completed\n'; this.todos.forEach((todo) => < fileContents += `$,$\n` >); return fs.writeFile('todos.csv', fileContents); > .
Первое отличие — это тот факт, что наша функция больше не принимает никакие аргументы. В случае с обещаниями нам не нужна функция обратного вызова. Второе отличие касается того, как написан файл. Теперь мы возвращаем результат обещания writeFile() .
Сохраните и закройте index.js .
Теперь давайте изменим наш тест так, чтобы он работал с обещаниями. Откройте index.test.js :
Замените тест saveToFile() на следующее:
todos/index.js
. describe("saveToFile()", function() < it("should save a single TODO", function() let todos = new Todos(); todos.add("save a CSV"); return todos.saveToFile().then(() => assert.strictEqual(fs.existsSync('todos.csv'), true); let expectedFileContents = "Title,Completed\nsave a CSV,false\n"; let content = fs.readFileSync("todos.csv").toString(); assert.strictEqual(content, expectedFileContents); >); >); >);
Первое, что нужно изменить, — это удалить обратный вызов done() из аргументов. Если Mocha передает аргумент done() , его необходимо вызвать или он выдаст ошибку такого типа:
1) saveToFile() should save a single TODO: Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves. (/home/ubuntu/todos/index.test.js) at listOnTimeout (internal/timers.js:536:17) at processTimers (internal/timers.js:480:7)
При тестировании обещаний не включайте обратный вызов done() в it() .
Для проверки обещания нам нужно задать код утверждения в функцию then() . Обратите внимание, что мы возвращаем это обещание в тест, и у нас нет функции catch() для перехвата при отклонении обещания .
Мы возвращаем обещание, чтобы любые ошибки, выданные в функции then() , всплыли в функции it() . Если ошибки не всплывают, Mocha не провалит тест. При тестировании обещаний вам нужно использовать return для тестируемого обещания . Если нет, вы рискуете получить ложный позитивный результат.
Также мы пропускаем выражение catch() , так как Mocha может обнаружить, когда обещание отклоняется. При отклонении тест автоматически проваливается.
Теперь, когда у нас есть тест, сохраните и закройте файл, затем запустите Mocha с npm test для подтверждения, что мы получим успешный результат:
Output. integrated test ✓ should be able to add and complete TODOs complete() ✓ should fail if there are no TODOs saveToFile() ✓ should save a single TODO 3 passing (18ms)
Мы изменили наш код и тест для использования обещаний, и теперь мы точно знаем, что это работает. Но последние асинхронные модели используют ключевые слова async / await , поэтому нам не нужно создавать множественные функции then() для обработки успешных результатов. Давайте посмотрим, как работает тест с async / await .
async/await
Ключевые слова async / await делают работу с обещаниями менее многословной. Когда мы определяем функцию как асинхронную с ключевым словом async , мы можем получить любые дальнейшие результаты в этой функции с ключевым словом await . Так мы можем использовать обещания без необходимости использования функций then() или catch() .
Можно упростить наш тест saveToFile() , который основан на обещании с async / await . В вашем текстовом редакторе создайте эти незначительные изменения к тесту saveToFile() в index.test.js :
todos/index.test.js
. describe("saveToFile()", function() < it("should save a single TODO", async function() let todos = new Todos(); todos.add("save a CSV"); await todos.saveToFile(); assert.strictEqual(fs.existsSync('todos.csv'), true); let expectedFileContents = "Title,Completed\nsave a CSV,false\n"; let content = fs.readFileSync("todos.csv").toString(); assert.strictEqual(content, expectedFileContents); >); >);
Первое изменение — это тот факт, что функция, используемая it() , имеет ключевое слово async , когда она определена. Это позволяет использовать ключевое слово await в ее теле.
Второе изменение обнаруживается, когда мы вызываем saveToFile() . Ключевое слово await используется перед вызовом. Теперь Node.js знает, что нужно ждать, пока эта функция не решится перед продолжением теста.
Код функции проще читать, когда мы переместили код, который был в функции then() в тело функции it() . Запуск этого кода с помощью npm test дает следующий вывод:
Output. integrated test ✓ should be able to add and complete TODOs complete() ✓ should fail if there are no TODOs saveToFile() ✓ should save a single TODO 3 passing (30ms)
Теперь мы можем тестировать асинхронные функции, используя любые три асинхронные парадигмы надлежащим образом.
Мы охватили много вопросов о тестировании синхронного и асинхронного кода с Mocha. Далее переходим к другой функции, которую Mocha предлагает для улучшения нашего опыта тестирования, в частности в том, что касается использования хуков для изменения тестовых сред.
Шаг 5 — Использование хуков для улучшения тестовых случаев
Хуки — полезный элемент Mocha, который позволяет нам настроить среду до и после теста. Обычно мы добавляем хуки в блок функции describe() , так как они содержат логику установки и сноса, специфичную для некоторых тестовых случаев.
Mocha предоставляет четыре типа хуков, которые используются в тестах:
- before : этот хук запускается один раз перед началом первого теста.
- beforeEach : этот хук запускается перед каждым тестовым случаем.
- after : этот хук запускается один раз после завершения последнего тестового случая.
- afterEach : этот хук запускается после каждого тестового случая.
Когда мы тестируем функцию или свойство несколько раз, хуки очень помогают, так как они позволяют нам отделять код установки теста (например создание объекта todos ) от кода утверждения теста.
Для просмотра значения хуков добавим больше тестов в наш блок теста saveToFile() .
Хотя мы подтвердили, что можем сохранить элементы списка TODO в файл, мы сохранили только один элемент. Более того, элемент не был помечен как завершенный. Добавим больше тестов, чтобы убедиться, что различные аспекты нашего модуля работают.
Сначала добавим второй тест для подтверждения того, что наш файл сохранен корректно, после завершения элемента списка TODO. Откройте файл index.test.js в своем текстовом редакторе:
Измените последний тест на следующее:
todos/index.test.js
. describe("saveToFile()", function () < it("should save a single TODO", async function () < let todos = new Todos(); todos.add("save a CSV"); await todos.saveToFile(); assert.strictEqual(fs.existsSync('todos.csv'), true); let expectedFileContents = "Title,Completed\nsave a CSV,false\n"; let content = fs.readFileSync("todos.csv").toString(); assert.strictEqual(content, expectedFileContents); >); it("should save a single TODO that's completed", async function () let todos = new Todos(); todos.add("save a CSV"); todos.complete("save a CSV"); await todos.saveToFile(); assert.strictEqual(fs.existsSync('todos.csv'), true); let expectedFileContents = "Title,Completed\nsave a CSV,true\n"; let content = fs.readFileSync("todos.csv").toString(); assert.strictEqual(content, expectedFileContents); >); >);
Тест аналогичен тому, что мы делали ранее. Основное отличие в том, что мы вызываем функцию complete() перед вызовом saveToFile() и что ожидаемые элементы файла expectedFileContents теперь имеют значение true вместо false для столбца completed .
Сохраните и закройте файл.
Запустим наш новый тест, а также все остальные с помощью npm test :
В результате вы получите следующий вывод:
Output. integrated test ✓ should be able to add and complete TODOs complete() ✓ should fail if there are no TODOs saveToFile() ✓ should save a single TODO ✓ should save a single TODO that's completed 4 passing (26ms)
Он работает, как и ожидалось. Но возможности для улучшения все еще есть. Они оба должны инстанцировать объект Todos в начале теста. По мере того как мы добавляем больше тестовых случаев, это быстро становится повторяющимся и отнимает память. Также каждый раз, когда мы запускаем тест, создается файл. Кто-то менее знакомый с модулем может ошибочно принять это за реальный вывод. Было бы неплохо очистить наши файлы вывода после тестирования.
Сделаем эти улучшения с помощью тестовых хуков. Мы используем хук beforeEach() для настройки тестовой конфигурации элементов TODO. Тестовая конфигурация — это любое последовательное состояние, используемое в тесте. В нашем случае тестовая конфигурация — это новый объект todos , в который уже добавлен один элемент TODO. Затем мы используем afterEach() для удаления файла, созданного тестом.
В index.test.js внесите следующие изменения в ваш последний тест для saveToFile() :
todos/index.test.js
. describe("saveToFile()", function () < beforeEach(function () this.todos = new Todos(); this.todos.add("save a CSV"); >); afterEach(function () if (fs.existsSync("todos.csv")) fs.unlinkSync("todos.csv"); > >); it("should save a single TODO without error", async function () < await this.todos.saveToFile(); assert.strictEqual(fs.existsSync("todos.csv"), true); let expectedFileContents = "Title,Completed\nsave a CSV,false\n"; let content = fs.readFileSync("todos.csv").toString(); assert.strictEqual(content, expectedFileContents); >); it("should save a single TODO that's completed", async function () < this.todos.complete("save a CSV"); await this.todos.saveToFile(); assert.strictEqual(fs.existsSync('todos.csv'), true); let expectedFileContents = "Title,Completed\nsave a CSV,true\n"; let content = fs.readFileSync("todos.csv").toString(); assert.strictEqual(content, expectedFileContents); >); >);
Давайте разберем все изменения, которые мы внесли. Мы добавили блок beforeEach() в тестовый блок:
todos/index.test.js
. beforeEach(function () this.todos = new Todos(); this.todos.add("save a CSV"); >); .
Эти две строки кода создают новый объект Todos , доступный для каждого нашего теста. С Mocha объект this в beforeEach() относится к такому же объекту this в it() . this одинаков для каждого блока кода внутри блока describe() . Подробнее о this ищите в нашем обучающем руководстве Понимание методов This, Bind, Call и Apply в JavaScript.
Благодаря мощному обмену контекстом мы можем быстро создавать тестовые конфигурации, которые подходят для обоих тестов.
Затем мы очищаем наш файл CSV в функции afterEach() :
todos/index.test.js
. afterEach(function () if (fs.existsSync("todos.csv")) fs.unlinkSync("todos.csv"); > >); .
Если тест не прошел, то он не мог создать файл. Поэтому мы проверяем наличие файла перед использованием функции unlinkSync() для его удаления.
Остальные изменения переключают ссылку с объектов todos , созданных ранее в функции it() , на this.todos , имеющиеся в контексте Mocha. Также мы удалили строки, которые ранее инстанциировали todos в отдельных тестовых случаях.
Теперь запустим этот файл, чтобы убедиться, что тест все еще работает. Введите в терминале npm test , чтобы получить следующее:
Output. integrated test ✓ should be able to add and complete TODOs complete() ✓ should fail if there are no TODOs saveToFile() ✓ should save a single TODO without error ✓ should save a single TODO that's completed 4 passing (20ms)
Результаты те же, и к тому же мы немного сократили время установки для новых тестов для функции saveToFile() и нашли решение для остаточного файла CSV.
Заключение
В этом обучающем руководстве мы написали модуль Node.js для управления элементами TODO и протестировали код вручную с помощью Node.js REPL. Затем создали тестовый файл и использовали фреймворк Mocha для запуска автоматизированных тестов. С помощью модуля assert мы смогли проверить корректность работы кода. Также протестировали синхронные и асинхронные функции с Mocha. Наконец, создали хуки с Mocha, которые делают написание связанных тестовых случаев более читабельным и управляемым.
С помощью этих знаний попробуйте самостоятельно написать тесты для новых модулей Node.js, созданных вами. Вы можете подумать о вводах и выводах вашей функции и написать тест до написания кода?
Если вы хотите узнать больше о тестовом фреймворке Mocha, ознакомьтесь с официальной документацией Mocha. Если вы хотите продолжить изучение Node.js, вы можете перейти к странице серии Написание кода на Node.js.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
Как запустить файл js в node js
![]()
Как запустить код JavaScript в Visual Studio Code
03 марта 2023
Оценки статьи
Еще никто не оценил статью
Иногда возникает необходимость запустить фрагмент кода JavaScript напрямую в Visual Studio Code (VSCode), чтобы проверить его работоспособность. В этой статье мы рассмотрим, как запустить код JavaScript в VS Code.
Установка Node.js на компьютер
Первым шагом для запуска JavaScript в VS Code является установка Node.js.
Node.js — это среда выполнения JavaScript, которая позволяет запускать JavaScript на стороне сервера.
Она включает в себя средства для выполнения JavaScript кода в командной строке, которые можно использовать для тестирования и отладки JavaScript кода.
Вы можете загрузить и установить Node.js с официального сайта по ссылке
Создайте файл JavaScript в VS Code
После установки Node.js вы можете создать файл JavaScript в VS Code.
Чтобы создать новый файл JavaScript, выберите File -> New File в меню VS Code. Затем сохраните файл с расширением .js (например, index.js).
Напишите JavaScript код
После создания файла JavaScript вы можете написать код, который хотите запустить. Например, давайте создадим новый массива на основе существующего массива с помощью map() :
let numbers = [1, 2, 3, 4, 5]; let squares = numbers.map(num => num ** 2); console.log(squares);
Запустите код
Теперь мы готовы запустить наш JavaScript код. Чтобы запустить код, выберите Terminal -> New Terminal в меню VS Code, чтобы открыть новую вкладку терминала. В терминале введите следующую команду: node index.js
где index.js — это имя файла, который вы создали ранее.
После выполнения этой команды вы увидите вывод в консоли:
>>> [ 1, 4, 9, 16, 25 ]

Это означает, что ваш JavaScript код успешно запущен в VS Code!
Вы можете также использовать VS Code для отладки JavaScript кода, используя встроенные средства отладки. Для этого вам нужно создать конфигурационный файл отладки (launch.json) и настроить его для запуска и отладки вашего JavaScript кода.
В заключение, запуск JavaScript кода в VS Code — это очень простой процесс, который можно выполнить всего за несколько шагов.
Установите Node.js, создайте файл JavaScript, напишите код и запустите его в терминале VS Code. Вы можете использовать этот процесс для разработки и отладки JavaScript приложений в VS Code.
Меню категорий
-
Загрузка категорий.
