Chrome Plugin Development – Automated Scripting (3)

Import/Export Scripts

Using sheet. Js js-xlsX library can be very convenient to implement import and export functions.

  1. Export function

In order to facilitate the recording of different personnel can share the script to achieve this function, but also for the later batch import script. The exported file format is as follows:

Multiple custom fields can be set in the script. For convenience and not conflict with fixed fields, try to use Chinese names.

Custom fieldOnly in theset-input-valueEvent to be set toSetting field Key

ExportScript () {// create a workBook let workBook = xlsx.utils.book_new () // create a workBook let workBook = xlsx.utils.book_new () // create a workBook let workBook = xlsx.utils.book_new ( => {// Create sheet object let sheetData = [] let headers = json.parse (json.stringify (fixedHeader)) // Extract the column that defines the field name in the eventList input event  item.eventList .filter(event => event.type === 'set-input-value' && event.key && ! headers.includes(event.key)) .forEach(event => { item[event.key] = event.value headers.unshift(event.key) }) let caseRow = {... item, eventList: JSON.stringify(item.eventList) } if (Array.isArray(item.responseConfig)) { caseRow.responseConfig = JSON.stringify(item.responseConfig) } sheetData.push(caseRow) let sheet = XLSX.utils.json_to_sheet(sheetData, {header: Xlsx.utils.book_append_sheet (workBook, sheet, item.name)}); // openDownloadDialog(workbookBlob, 'automation script.xlsx ')}Copy the code
  1. The import function

Scripts may need to be executed repeatedly in some scenarios. If you do not import them in batches, you need to modify them each timeCustom fieldIf you have a lot of Settings it can be very difficult to change. We can edit it in an XLSX file and import it directly, like this

Devtool after import:

Parsing XLSX code

importScript (file) { readWorkbookFromLocalFile(file, wb => { /** * workBook => caseList:[] * 1. First loop sheets to know how many scripts there are * 2. Then loop lines in each sheet to know how many use cases there are in each script * 3. Let caseList = [] wb.sheetnames. forEach(sheetName => {let xlsxData = XLSX.utils.sheet_to_json(wb.Sheets[sheetName]) let allKeyList = getHeaderKeyList(wb.Sheets[sheetName]) let customKeyList  = allKeyList.filter(key => ! fixedHeader.includes(key)) let baseCaseDetail = {} let baseEventList = [] xlsxData.forEach((data, If (index === 0) {baseCaseDetail = {name: data.name, urlPath: data.urlPath, width: data.width, height: data.height } if (data.responseConfig && data.responseConfig.length > 5) { baseCaseDetail.responseConfig = JSON.parse(data.responseConfig) } try { baseEventList = JSON.parse(data.eventList) || [] } catch (e) { Console. error(' failed to parse eventList ', ForEach (event => {if (event.type === 'set-input-value' &&) {if (event.type === 'set-input-value' &&) {if (event.type === 'set-input-value' &&  customKeyList.includes(event.key)) { event.value = data[event.key] } eventList.push(event) }) caseList.push({ ... baseCaseDetail, name: baseCaseDetail.name + '-' + index, eventList: JSON.parse(JSON.stringify(eventList)) }) }) }) this.$store.commit('setCaseList', caseList) this.importFlag = true }) return false }Copy the code

Single script – run different variables multiple times

Usage scenario: each website form automatically input submission, the above import function has included this function

A script that calls a third-party web site

The biggest function of this optimization is this, which can have a lot of space for imagination. Since our company is engaged in human resources outsourcing, the handling personnel always need to perform frequent operations such as entry, transfer, sealing and unsealing of the operators of the government social security website. So I want to do this function to save staff’s workload and improve efficiency.

Step 1 Configurationmanifest.json

The externally_connectable field defines sites that can use the Chrome.* API directly. Some wildcard configurations are not supported, so the domain name needs to be precise.

"externally_connectable": {
  "matches": ["http://localhost:63342/*"]
}
Copy the code

The second step in the web page informs the third party website which script to execute

Here we need to know how to notify the third party website. First, the third party website needs to open devTool before we can execute the script.

You can then use the Chrome.* API to send messages to background.js from the configuration page

<! DOCTYPE HTML > < HTML lang="en"> <head> <meta charset="UTF-8"> <title> < span > tabId < / span > < input id = "tabId" value = "759" / > < / div > < div > < span > script name < / span > < input id = "name" value = "nuggets search" / > < / div > <div> <span> <input ID ="key" value=" ha ha "/> </div> <button ID ="button-1"> <span> <span> <pre ID ="response"></pre> </div> <script SRC ="autoScript/js/jquery-1.8.3.js"></script> <script> $('#button-1').on('click', sendMessage) function sendMessage () { let editorExtensionId = 'odfckenjjgjokihccfabfoecjclggmka' let tabId = $('#tabId')[0].value let name = $('#name')[0].value let key = $('#key')[0].value chrome.runtime.sendMessage( EditorExtensionId, {tabId: tabId, data: {type: 'run-case', name: name, customKey: {' search keyword ': key}}}, (response) => { $('#response').text(JSON.stringify(response, null, 2)) console.log(response.success) } ) } </script> </body> </html>Copy the code

The third step, background.js, distributes the request

This part is relatively simple and does not use the long link postMessage because it cannot be called back, so it is not very convenient to notify the result of the original web request.

/ / to monitor externally_connectable configuration of normal web messages sent chrome. Runtime. OnMessageExternal. AddListener (function (request, the sender, SendResponse) {if (request.tabid in connections) {// Do not send messages using long connections because callback cannot be set // connections[request.tabId].postMessage(request.data) chrome.runtime.sendMessage(request, Response => {sendResponse(response)}) return true} else {sendResponse({error: 'onMessageExternal Tab not found in connection list.'}) } })Copy the code

Step 4 Devtool of a third-party web page listens for message execution and returns

Main. Vue / * * * long connection without sendResponse callback, so use this way callback * / chrome. Runtime. OnMessage. AddListener ((MSG, sender, sendResponse) => { let message = msg.data console.log('devtool chrome.runtime.onMessage', msg) if (+msg.tabId === +chrome.devtools.inspectedWindow.tabId && message) { switch (message.type) { case 'run-case': / / 1. Let index = this.caselist.findIndex (item => item.name === message.name) if (index < 0) {return} let newCase = JSON.parse(JSON.stringify(this.caseList[index])) newCase.eventList = newCase.eventList.map(event => { if (event.type === 'set-input-value' && event.key in message.customKey) { event.value = message.customKey[event.key] } return event }) Vue.set(this.caseList, index, newCase) this.$EventBus.$emit('run-case', {index, SendResponse}) // Send to the actual executing page return true}}})Copy the code
home.vue

this.$EventBus.$on('run-case', async ({index, sendResponse}) => {
  await this.runCase(index)
  sendResponse(this.result[this.caseList[index].name])
})
Copy the code

At this point, we are ready to call the scripts that have been recorded on other pages on our own page.

Complete demo

Import/Export demo

Invoke third-party site scripts to demonstrate