Skip to content

Commit

Permalink
Merge pull request #3 from Badgerati/develop
Browse files Browse the repository at this point in the history
v0.11.0
  • Loading branch information
Badgerati committed Aug 1, 2019
2 parents 076009b + 3e509c8 commit 4ee381b
Show file tree
Hide file tree
Showing 5 changed files with 265 additions and 118 deletions.
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Monocle

[![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/Badgerati/Monocle/master/LICENSE.txt)
[![PowerShell](https://img.shields.io/powershellgallery/dt/monocle.svg?label=PowerShell&colorB=085298)](https://www.powershellgallery.com/packages/Monocle)

Monocle is a PowerShell Web Automation module, made to make automating and testing websites easier.

## Install
Expand Down Expand Up @@ -27,10 +30,10 @@ Start-MonocleFlow -Name 'Load YouTube' -ScriptBlock {
Set-MonocleUrl -Url 'https://www.youtube.com'
# Sets the search bar element to the passed value to query
Set-MonocleElementValue -ElementName 'search_query' -Value 'Beerus Madness (Extended)'
Set-MonocleElementValue -Id 'search_query' -Value 'Beerus Madness (Extended)'
# Tells the browser to click the search button
Invoke-MonocleElementClick -ElementName 'search-btn'
Invoke-MonocleElementClick -Id 'search-btn'
# Though all commands sleep when the page is busy, some buttons use javascript
# to reform the page. The following will sleep the browser until the passed URL is loaded.
Expand All @@ -42,7 +45,7 @@ Start-MonocleFlow -Name 'Load YouTube' -ScriptBlock {
Save-MonocleImage -MPath 'div[@data-context-item-id=SI6Yyr-iI6M]/img[0]' -Path '.\beerus.jpg'
# Tells the browser to click the video in the results. The video link is found via MPath
Invoke-MonocleElementClick -MPath -ElementName 'a[@title=Dragon Ball Super Soundtrack - Beerus Madness (Extended) - Duration: 10:00.]'
Invoke-MonocleElementClick -MPath 'a[@title=Dragon Ball Super Soundtrack - Beerus Madness (Extended) - Duration: 10:00.]'
# Again, we expect the URL to be loaded
Wait-MonocleUrl -Url 'https://www.youtube.com/watch?v=SI6Yyr-iI6M'
Expand Down
9 changes: 5 additions & 4 deletions examples/youtube.ps1
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
$path = Split-Path -Parent -Path (Split-Path -Parent -Path $MyInvocation.MyCommand.Path)
Import-Module "$($path)/src/Monocle.psm1" -Force -ErrorAction Stop
$path = "$($path)/src/Monocle.psm1"
Import-Module $path -Force -ErrorAction Stop

# Monocle runs commands in web flows, for easy disposal and test tracking
# Each flow needs a name
Expand All @@ -9,10 +10,10 @@ Start-MonocleFlow -Name 'Load YouTube' -ScriptBlock {
Set-MonocleUrl -Url 'https://www.youtube.com'

# Sets the search bar element to the passed value to query
Set-MonocleElementValue -ElementName 'search_query' -Value 'Beerus Madness (Extended)'
Set-MonocleElementValue -Id 'search_query' -Value 'Beerus Madness (Extended)'

# Tells the browser to click the search button
Invoke-MonocleElementClick -ElementName 'search-btn'
Invoke-MonocleElementClick -Id 'search-btn'

# Though all commands sleep when the page is busy, some buttons use javascript
# to reform the page. The following will sleep the browser until the passed URL is loaded.
Expand All @@ -24,7 +25,7 @@ Start-MonocleFlow -Name 'Load YouTube' -ScriptBlock {
Save-MonocleImage -MPath 'div[@data-context-item-id=SI6Yyr-iI6M]/img[0]' -Path '.\beerus.jpg'

# Tells the browser to click the video in the results. The video link is found via MPath
Invoke-MonocleElementClick -MPath -ElementName 'a[@title=Dragon Ball Super Soundtrack - Beerus Madness (Extended) - Duration: 10:00.]'
Invoke-MonocleElementClick -MPath 'a[@title=Dragon Ball Super Soundtrack - Beerus Madness (Extended) - Duration: 10:00.]'

# Again, we expect the URL to be loaded
Wait-MonocleUrl -Url 'https://www.youtube.com/watch?v=SI6Yyr-iI6M'
Expand Down
Binary file modified src/Monocle.psd1
Binary file not shown.
172 changes: 125 additions & 47 deletions src/Private/Elements.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -14,97 +14,175 @@ function Get-MonocleElement
[CmdletBinding()]
param (
[Parameter(Mandatory=$true)]
[ValidateNotNull()]
[ValidateSet('Id', 'Tag', 'MPath')]
[string]
$Name,
$FilterType,

[Parameter()]
[string]
$TagName = $null,
$Id,

[Parameter()]
[string]
$AttributeName = $null,
$TagName,

[switch]
$FindByValue,
[Parameter()]
[string]
$AttributeName,

[Parameter()]
[string]
$AttributeValue,

[Parameter()]
[string]
$ElementValue,

[Parameter()]
[string]
$MPath,

[switch]
$NoThrow,
$NoThrow
)

switch ($FilterType.ToLowerInvariant()) {
'id' {
return (Get-MonocleElementById -Id $Id -NoThrow:$NoThrow)
}

'tag' {
if ([string]::IsNullOrWhiteSpace($AttributeName)) {
return (Get-MonocleElementByTagName -TagName $TagName -ElementValue $ElementValue -NoThrow:$NoThrow)
}
else {
return (Get-MonocleElementByTagName -TagName $TagName -AttributeName $AttributeName -AttributeValue $AttributeValue -ElementValue $ElementValue -NoThrow:$NoThrow)
}
}

'mpath' {
return (Get-MonocleElementByMPath -MPath $MPath -NoThrow:$NoThrow)
}
}
}

function Get-MonocleElementById
{
[CmdletBinding()]
param (
[Parameter(Mandatory=$true)]
[string]
$Id,

[switch]
$MPath
$NoThrow
)

$document = $Browser.Document

# if it's set, find element based on mpath
if ($MPath -and ![string]::IsNullOrWhiteSpace($Name))
{
$element = Resolve-MonocleMPath -MPath $Name
Write-Verbose -Message "Finding element with identifier '$Id'"
$element = $document.IHTMLDocument3_getElementById($Id)

# throw error if can't find element
if ((Test-MonocleElementNull -Element $element) -and !$NoThrow) {
throw "Cannot find any element based on the MPath supplied: $Name"
}
# if no element by ID, try by first named element
if (Test-MonocleElementNull -Element $element) {
Write-Verbose -Message "Finding element with name '$Id'"
$element = $document.IHTMLDocument3_getElementsByName($Id) | Select-Object -First 1
}

return $element
# throw error if can't find element
if ((Test-MonocleElementNull -Element $element) -and !$NoThrow) {
throw "Element with ID/Name of '$Id' not found"
}

# if they're set, retrieve element by tag/attribute value combo
if (![string]::IsNullOrWhiteSpace($TagName) -and ![string]::IsNullOrWhiteSpace($AttributeName))
return $element
}

function Get-MonocleElementByTagName
{
[CmdletBinding()]
param (
[Parameter(Mandatory=$true)]
[string]
$TagName,

[Parameter(Mandatory=$true, ParameterSetName='Attribute')]
[string]
$AttributeName,

[Parameter(Mandatory=$true, ParameterSetName='Attribute')]
[string]
$AttributeValue,

[Parameter()]
[string]
$ElementValue,

[switch]
$NoThrow
)

$document = $Browser.Document

# get all elements for the tag
$elements = $document.IHTMLDocument3_getElementsByTagName($TagName)

# if we have attribute info, attempt to get an element
if ($PSCmdlet.ParameterSetName -ieq 'Attribute')
{
Write-Verbose -Message "Finding element with tag <$TagName>, attribute '$AttributeName' and value '$Name'"
Write-Verbose -Message "Finding element with tag <$TagName>, attribute '$AttributeName' with value '$AttributeValue'"

$element = $document.IHTMLDocument3_getElementsByTagName($TagName) |
Where-Object { $_.getAttribute($AttributeName) -imatch $Name } |
Select-Object -First 1
$elements = $elements |
Where-Object { $_.getAttribute($AttributeName) -imatch $AttributeValue }

# throw error if can't find element
if ((Test-MonocleElementNull -Element $element) -and !$NoThrow) {
throw "Element <$TagName> with attribute '$AttributeName' value of $Name not found."
if ((Test-MonocleElementNull -Element ($elements | Select-Object -First 1)) -and !$NoThrow) {
throw "Element <$TagName> with attribute '$AttributeName' and value of '$AttributeValue' not found"
}

return $element
}

# if they're set, retrieve the element by tag/value combo (value then innerHTML)
if (![string]::IsNullOrWhiteSpace($TagName) -and $FindByValue)
if (![string]::IsNullOrWhiteSpace($ElementValue))
{
Write-Verbose -Message "Finding element with tag <$TagName>, and value '$Name'"
$elements = $document.IHTMLDocument3_getElementsByTagName($TagName)
Write-Verbose -Message "Finding element with tag <$TagName>, and value '$ElementValue'"

$element = $elements |
Where-Object { $_.value -ieq $Name }
Where-Object { $_.value -imatch $ElementValue }
Select-Object -First 1

if (Test-MonocleElementNull -Element $element) {
$element = $elements |
Where-Object { $_.innerHTML -ieq $Name }
Where-Object { $_.innerHTML -imatch $ElementValue }
Select-Object -First 1
}

# throw error if can't find element
if ((Test-MonocleElementNull -Element $element) -and !$noThrow) {
throw "Element <$TagName> with value of $Name not found."
throw "Element <$TagName> with value of '$ElementValue' not found"
}

return $element
}
else {
$element = ($elements | Select-Object -First 1)
}

# if no tag/attr combo, attempt to retrieve by ID
Write-Verbose -Message "Finding element with identifier '$Name'"
$element = $document.IHTMLDocument3_getElementById($Name)
return $element
}

# if no element by ID, try by first named element
if (Test-MonocleElementNull -Element $element) {
Write-Verbose -Message "Finding element with name '$Name'"
$element = $document.IHTMLDocument3_getElementsByName($Name) | Select-Object -First 1
}
function Get-MonocleElementByMPath
{
[CmdletBinding()]
param (
[Parameter(Mandatory=$true)]
[string]
$MPath,

[switch]
$NoThrow
)

$element = Resolve-MonocleMPath -MPath $MPath

# throw error if can't find element
if ((Test-MonocleElementNull -Element $element) -and !$NoThrow) {
throw "Element with ID/Name of $Name not found."
throw "Cannot find any element based on the MPath supplied: $MPath"
}

return $element
Expand Down
Loading

0 comments on commit 4ee381b

Please sign in to comment.