@dhlab/e2e-autogen
Version:
Google 스프레드시트 기반 시나리오를 Playwright 테스트 스텁 코드로 자동 생성하고, 테스트 실행 결과를 다시 시트에 업데이트하는 CLI 도구
242 lines (240 loc) • 12.4 kB
JavaScript
'use strict';
var _SpreadsheetSheet_instances, _SpreadsheetSheet_gid, _SpreadsheetSheet_cachedSheetName, _SpreadsheetSheet_cachedColumnCount, _SpreadsheetSheet_rawSheets, _SpreadsheetSheet_dataRange, _SpreadsheetSheet_ensureColumnExists, _SpreadsheetSheet_columnCount, _SpreadsheetSheet_numberToColumnLetter, _SpreadsheetSheet_columnLetterToNumber;
Object.defineProperty(exports, "__esModule", { value: true });
exports.SpreadsheetSheet = void 0;
const tslib_1 = require("tslib");
class SpreadsheetSheet {
constructor(spreadsheetId, gid, sheets, rawSheets) {
_SpreadsheetSheet_instances.add(this);
_SpreadsheetSheet_gid.set(this, void 0);
_SpreadsheetSheet_cachedSheetName.set(this, null);
_SpreadsheetSheet_cachedColumnCount.set(this, null);
_SpreadsheetSheet_rawSheets.set(this, void 0);
this.spreadsheetId = spreadsheetId;
tslib_1.__classPrivateFieldSet(this, _SpreadsheetSheet_gid, gid, "f");
this.sheets = sheets;
tslib_1.__classPrivateFieldSet(this, _SpreadsheetSheet_rawSheets, rawSheets || null, "f");
}
get gid() {
return tslib_1.__classPrivateFieldGet(this, _SpreadsheetSheet_gid, "f");
}
async rows() {
const sheetName = await this.sheetName();
const res = await this.sheets.spreadsheets.values.get({
spreadsheetId: this.spreadsheetId,
range: `'${sheetName}'`,
});
return res.data.values ?? [];
}
/**
* 지정된 셀에 comment를 추가합니다.
* @param row 행 번호 (1-based)
* @param col 열 번호 (1-based)
* @param comment 추가할 comment 내용
*/
async addComment(row, col, comment) {
if (!comment.trim())
return;
const sheetName = await this.sheetName();
const columnLetter = tslib_1.__classPrivateFieldGet(this, _SpreadsheetSheet_instances, "m", _SpreadsheetSheet_numberToColumnLetter).call(this, col);
const range = `'${sheetName}'!${columnLetter}${row}`;
try {
await this.sheets.spreadsheets.batchUpdate({
spreadsheetId: this.spreadsheetId,
requestBody: {
requests: [
{
updateCells: {
range: {
sheetId: parseInt(tslib_1.__classPrivateFieldGet(this, _SpreadsheetSheet_gid, "f")),
startRowIndex: row - 1,
endRowIndex: row,
startColumnIndex: col - 1,
endColumnIndex: col,
},
rows: [
{
values: [
{
note: comment,
},
],
},
],
fields: "note",
},
},
],
},
});
}
catch (error) {
console.warn(`⚠️ Failed to add comment to ${range}: ${error}`);
}
}
/**
* values를 마지막 컬럼 다음에 세로 방향으로 추가한다.
* @param values 추가할 데이터
* @param startRow 데이터가 시작되는 row (default: 1)
*/
async writeAfterLastColumn(values, startRow = 1) {
if (values.length === 0) {
console.warn("⚠️ 작성할 데이터가 없습니다. writeAfterLastColumn 스킵");
return;
}
const { nextColumnLetter: targetColumnLetter, lastRow } = await tslib_1.__classPrivateFieldGet(this, _SpreadsheetSheet_instances, "m", _SpreadsheetSheet_dataRange).call(this);
// 시트 컬럼 수가 부족하면 확장
const targetColumnNum = tslib_1.__classPrivateFieldGet(this, _SpreadsheetSheet_instances, "m", _SpreadsheetSheet_columnLetterToNumber).call(this, targetColumnLetter);
await tslib_1.__classPrivateFieldGet(this, _SpreadsheetSheet_instances, "m", _SpreadsheetSheet_ensureColumnExists).call(this, targetColumnNum);
const sheetName = await this.sheetName();
// 시트에 이미 존재하는 데이터 행 수
const existingDataRows = Math.max(0, lastRow - (startRow - 1));
const totalRows = Math.max(existingDataRows, values.length);
// 부족한 행은 빈 셀로 패딩
const padded = values.map((v) => [...v]);
while (padded.length < totalRows)
padded.push([""]);
const endRow = startRow + padded.length - 1;
const range = `'${sheetName}'!${targetColumnLetter}${startRow}:${targetColumnLetter}${endRow}`;
await this.sheets.spreadsheets.values.update({
spreadsheetId: this.spreadsheetId,
range,
valueInputOption: "RAW",
requestBody: { values: padded },
});
console.log(`✅ ${values.length} rows written → ${range}`);
}
/**
* values 를 마지막 행 다음(A열 기준) 에 가로 방향으로 추가한다.
* @param values 추가할 데이터
*/
async writeAfterLastRow(values) {
if (values.length === 0) {
console.warn("⚠️ 작성할 데이터가 없습니다. writeAfterLastRow 스킵");
return;
}
const sheetName = await this.sheetName();
const { lastRow } = await tslib_1.__classPrivateFieldGet(this, _SpreadsheetSheet_instances, "m", _SpreadsheetSheet_dataRange).call(this);
const startRow = lastRow + 1;
const columnCount = Math.max(...values.map((v) => v.length));
const endColumnLetter = tslib_1.__classPrivateFieldGet(this, _SpreadsheetSheet_instances, "m", _SpreadsheetSheet_numberToColumnLetter).call(this, columnCount);
const range = `'${sheetName}'!A${startRow}:${endColumnLetter}${startRow + values.length - 1}`;
await this.sheets.spreadsheets.values.update({
spreadsheetId: this.spreadsheetId,
range,
valueInputOption: "RAW",
requestBody: { values: values },
});
}
async applyStyle(requests) {
if (!requests || requests.length === 0)
return;
await this.sheets.spreadsheets.batchUpdate({
spreadsheetId: this.spreadsheetId,
requestBody: { requests },
});
}
/**
* gid를 이용해 시트 이름을 조회한다.
*/
async sheetName() {
if (tslib_1.__classPrivateFieldGet(this, _SpreadsheetSheet_cachedSheetName, "f")) {
return tslib_1.__classPrivateFieldGet(this, _SpreadsheetSheet_cachedSheetName, "f");
}
if (tslib_1.__classPrivateFieldGet(this, _SpreadsheetSheet_rawSheets, "f")) {
const sheetsData = await tslib_1.__classPrivateFieldGet(this, _SpreadsheetSheet_rawSheets, "f").call(this);
const targetSheet = sheetsData.find((sheet) => String(sheet.properties?.sheetId) === tslib_1.__classPrivateFieldGet(this, _SpreadsheetSheet_gid, "f"));
if (targetSheet?.properties?.title) {
tslib_1.__classPrivateFieldSet(this, _SpreadsheetSheet_cachedSheetName, targetSheet.properties.title, "f");
return tslib_1.__classPrivateFieldGet(this, _SpreadsheetSheet_cachedSheetName, "f");
}
}
try {
const response = await this.sheets.spreadsheets.get({
spreadsheetId: this.spreadsheetId,
});
const targetSheet = response.data.sheets?.find((sheet) => String(sheet.properties?.sheetId) === tslib_1.__classPrivateFieldGet(this, _SpreadsheetSheet_gid, "f"));
const name = targetSheet?.properties?.title;
if (!name)
throw new Error(`gid(${tslib_1.__classPrivateFieldGet(this, _SpreadsheetSheet_gid, "f")})에 해당하는 시트를 찾지 못했습니다.`);
tslib_1.__classPrivateFieldSet(this, _SpreadsheetSheet_cachedSheetName, name, "f");
return name;
}
catch (error) {
throw new Error(`시트 이름 조회 실패: ${error}`);
}
}
invalidateCache() {
tslib_1.__classPrivateFieldSet(this, _SpreadsheetSheet_cachedSheetName, null, "f");
tslib_1.__classPrivateFieldSet(this, _SpreadsheetSheet_cachedColumnCount, null, "f");
}
}
exports.SpreadsheetSheet = SpreadsheetSheet;
_SpreadsheetSheet_gid = new WeakMap(), _SpreadsheetSheet_cachedSheetName = new WeakMap(), _SpreadsheetSheet_cachedColumnCount = new WeakMap(), _SpreadsheetSheet_rawSheets = new WeakMap(), _SpreadsheetSheet_instances = new WeakSet(), _SpreadsheetSheet_dataRange =
/**
* 시트의 데이터 범위를 감지한다.
*/
async function _SpreadsheetSheet_dataRange() {
const rows = await this.rows();
const lastColumnNum = Math.max(1, ...rows.map((row) => row.length));
const lastRow = rows.length;
const lastColumnLetter = tslib_1.__classPrivateFieldGet(this, _SpreadsheetSheet_instances, "m", _SpreadsheetSheet_numberToColumnLetter).call(this, lastColumnNum);
const nextColumnLetter = tslib_1.__classPrivateFieldGet(this, _SpreadsheetSheet_instances, "m", _SpreadsheetSheet_numberToColumnLetter).call(this, lastColumnNum + 1);
return {
lastRow,
lastColumnLetter,
nextColumnLetter,
};
}, _SpreadsheetSheet_ensureColumnExists = async function _SpreadsheetSheet_ensureColumnExists(columnNumber) {
const columnCount = await tslib_1.__classPrivateFieldGet(this, _SpreadsheetSheet_instances, "m", _SpreadsheetSheet_columnCount).call(this);
if (columnCount >= columnNumber)
return;
const append = {
appendDimension: {
sheetId: Number(tslib_1.__classPrivateFieldGet(this, _SpreadsheetSheet_gid, "f")),
dimension: "COLUMNS",
length: columnNumber - columnCount,
},
};
await this.sheets.spreadsheets.batchUpdate({
spreadsheetId: this.spreadsheetId,
requestBody: { requests: [append] },
});
this.invalidateCache();
console.log(`📐 시트 컬럼 확장: ${columnCount} → ${columnNumber}`);
}, _SpreadsheetSheet_columnCount = async function _SpreadsheetSheet_columnCount() {
if (tslib_1.__classPrivateFieldGet(this, _SpreadsheetSheet_cachedColumnCount, "f") !== null) {
return tslib_1.__classPrivateFieldGet(this, _SpreadsheetSheet_cachedColumnCount, "f");
}
if (tslib_1.__classPrivateFieldGet(this, _SpreadsheetSheet_rawSheets, "f")) {
const sheetsData = await tslib_1.__classPrivateFieldGet(this, _SpreadsheetSheet_rawSheets, "f").call(this);
const targetSheet = sheetsData.find((sheet) => String(sheet.properties?.sheetId) === tslib_1.__classPrivateFieldGet(this, _SpreadsheetSheet_gid, "f"));
const columnCount = targetSheet?.properties?.gridProperties?.columnCount;
if (columnCount !== undefined && columnCount !== null) {
tslib_1.__classPrivateFieldSet(this, _SpreadsheetSheet_cachedColumnCount, columnCount, "f");
return columnCount;
}
}
const response = await this.sheets.spreadsheets.get({
spreadsheetId: this.spreadsheetId,
includeGridData: false,
});
const targetSheet = response.data.sheets?.find((sheet) => String(sheet.properties?.sheetId) === tslib_1.__classPrivateFieldGet(this, _SpreadsheetSheet_gid, "f"));
const columnCount = targetSheet?.properties?.gridProperties?.columnCount ?? 0;
tslib_1.__classPrivateFieldSet(this, _SpreadsheetSheet_cachedColumnCount, columnCount, "f");
return columnCount;
}, _SpreadsheetSheet_numberToColumnLetter = function _SpreadsheetSheet_numberToColumnLetter(num) {
let result = "";
while (num > 0) {
num--;
result = String.fromCharCode(65 + (num % 26)) + result;
num = Math.floor(num / 26);
}
return result;
}, _SpreadsheetSheet_columnLetterToNumber = function _SpreadsheetSheet_columnLetterToNumber(columnLetter) {
let result = 0;
for (let i = 0; i < columnLetter.length; i++) {
result = result * 26 + (columnLetter.charCodeAt(i) - 64);
}
return result;
};